sfsys.c 240 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082
  1. /* RWD version 2022 to support PVOCEX format for Release 8*/
  2. /*
  3. * Copyright (c) 1983-2013 Martin Atkins, Richard Dobson and Composers Desktop Project Ltd
  4. * http://www.rwdobson.com
  5. * http://www.composersdesktop.com
  6. *
  7. This file is part of the CDP System.
  8. The CDP System is free software; you can redistribute it
  9. and/or modify it under the terms of the GNU Lesser General Public
  10. License as published by the Free Software Foundation; either
  11. version 2.1 of the License, or (at your option) any later version.
  12. The CDP System is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. GNU Lesser General Public License for more details.
  16. You should have received a copy of the GNU Lesser General Public
  17. License along with the CDP System; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  19. 02111-1307 USA
  20. *
  21. */
  22. /* sfsys 64bit (sfsys2010): handle files up to 4GB : fpos_t/fread/POS64 version */
  23. /* PC requires FILE64_WIN defined at compiler level */
  24. /*
  25. * portable sfsys replacement
  26. */
  27. /*RWD.6.5.99 test version for PEAK chunk, etc...
  28. *RWD.7.99 delete created file on error in format, etc
  29. *RWD Jan 2004: fixed WAVE_EX GUID reading on big-endian
  30. */
  31. /* Nov 2005: allow any channel count for B-Format files */
  32. /* April 2006: correct bug recoignising .ambi extension in gettypefrom name98() */
  33. /* but we don't really need to preserve this anyway...could just remove */
  34. /*April 2006: revise rdwavhdr to scan all chunks, so can pick up PEAK chunk after data chunk,
  35. as done by SoundForge! */
  36. /* Oct 2006: changed defs of WORD and DWORD to unsigned, can we support 4GB files???? */
  37. /* RWD 2009: first version of 64bit file handling for 4GB files.*/
  38. /* RWD May 2011: hacked rdwavhdr to accept dastardly Wavelab files with 20byte fmt chunk */
  39. /* PS: and also even more dastardly PT plain wave files with 40byte fmt chunk! */
  40. /* RWD Jan 2013 fixed bug in getsfsysadtl, return correct padded size */
  41. /* RWD Nov 2013 RELEASE 7: added MC_SURR_6_1 */
  42. /* still TODO: replace tmpnam with mkstemp for CDP temporary files for GUI progs (see below)
  43. * Or: leave it to the GUI progs to sort out! */
  44. /* RWD Feb 2014: converted to ints for x64 building */
  45. /* RWD MAR 2015 finished (?) adoption of default value for CDP_SOUND_EXT, eliminated various compiler warnings */
  46. #ifdef __GNUC__
  47. # if (defined(__LP64__) || defined(_LP64))
  48. # define CDPLONG64
  49. # endif
  50. #endif
  51. #ifdef CDPLONG64
  52. # define CDPLONG int
  53. #else
  54. # define CDPLONG long
  55. #endif
  56. //static char *rcsid = "$Id: sfsys.c%v 4.0 1998/17/02 00:47:05 martin Exp $";
  57. /*pstring for AIFC - includes the pad byte*/
  58. static const char aifc_floatstring[10] = { 0x08,'F','l','o','a','t',0x20,'3','2',0x00};
  59. static const char aifc_notcompressed[16] = {0x0e,'n','o','t',0x20,'c','o','m','p','r','e','s','s','e','d',0x00};
  60. /*
  61. * global state
  62. */
  63. int _sfverno = 0x801; //RWD: remember to update this!
  64. /* NB: private flag! */
  65. #define SFILE_ANAL (3) /* RWD Nov 2009: no PEAK,CLUE chunk for analysis files */
  66. #ifdef DEBUG_MAC
  67. #include <errno.h>
  68. static void parse_errno(int err)
  69. {
  70. switch(err){
  71. case(EBADF):
  72. printf("fd is not valid descriptor\n");
  73. break;
  74. case(EINVAL):
  75. printf("fd is socket, not a file\n");
  76. printf("or: file not open for writing\n");
  77. break;
  78. default:
  79. printf("unrecognised value for err: %d\n",err);
  80. break;
  81. }
  82. }
  83. #endif
  84. /*
  85. * $Log: sfsys.c%v $
  86. * Revision 2.2 1994/12/13 00:47:05 martin
  87. * Add declaration for Unix
  88. *
  89. * Revision 2.1 1994/10/31 15:49:10 martin
  90. * New version number to differentiate from versions already shipped
  91. *
  92. * Revision 1.1 1994/10/31 15:41:38 martin
  93. * Initial revision
  94. *
  95. */
  96. /* RWD July 1997: Revision 2.3: add support for new WAV float format
  97. RWD OCT 97: IMPORTANT FIX: DEAL WITH EXTRA 2 BYTES IN NEW WAVEFORMATEX CHUNK
  98. We MUST READ wave files correctly; it is not wrong, as such, to continue to write them
  99. the old way, (at least, for straight PCM format), but it is nevertheless inconsistent
  100. with modern practice.
  101. also: completed support for 8bit infiles (read,seek,dirsf)
  102. added initial support of minimal 'fact' chunk in WAVE files for non-PCM formats
  103. to use: #define CDP97
  104. to use Win32 file functions, define CDP99
  105. */
  106. #include <stdio.h>
  107. #ifdef unix
  108. #include <unistd.h>
  109. # ifdef __MAC__
  110. # include <sys/syslimits.h>
  111. # endif
  112. #endif
  113. #include <stdlib.h>
  114. #include <math.h>
  115. #include <string.h>
  116. #include <stdint.h>
  117. #ifdef _WIN32
  118. #include <windows.h>
  119. #include <mmreg.h>
  120. #endif
  121. #include <fcntl.h>
  122. #include <sys/types.h>
  123. #include <sys/stat.h>
  124. #if defined(_WIN32) || defined(__SC__) || defined (__GNUWIN32__)
  125. #include <io.h>
  126. //extern char* _fullpath (char*, const char*, size_t);
  127. #endif
  128. #include <errno.h>
  129. #include <stdio.h>
  130. #include <time.h>
  131. #ifdef _DEBUG
  132. #include <assert.h>
  133. #endif
  134. #include <sfsys.h> /*RWD: don't want local copies of this!*/
  135. /*RWD April 2005 */
  136. #include "sffuncs.h"
  137. #include "osbind.h"
  138. #ifdef _WIN32
  139. #include "alias.h"
  140. #endif
  141. int CDP_COM_READY = 0; /*global flag, ah well...(define in alias.h will access func??)*/
  142. /* RWD see line ~431; this is basically a mess; difficult to manage order of includes etc in WIN32 - blame windows.h! */
  143. #ifdef unix
  144. # ifdef ENABLE_PVX
  145. # include "pvfileio.h"
  146. # endif
  147. #endif
  148. #include "chanmask.h"
  149. /* RWD oct 2022 to eliminate pointer aliasing in AIFF srate handling */
  150. #include "ieee80.h"
  151. //static char *sfsys_h_rcsid = SFSYS_H_RCSID;
  152. /*
  153. * The portability definitions come first
  154. */
  155. #ifdef unix
  156. #define _O_BINARY (0)
  157. #define _O_RDWR O_RDWR
  158. #define _O_RDONLY O_RDONLY
  159. #define _O_CREAT O_CREAT
  160. #define _O_TRUNC O_TRUNC
  161. #define _O_EXCL O_EXCL
  162. #define _S_IWRITE S_IWRITE
  163. #define _S_IREAD S_IREAD
  164. #define chsize ftruncate
  165. #endif
  166. #if !defined(_WIN32) && !defined(__GNUC__)
  167. #define __inline /**/
  168. #endif
  169. #if defined __MAC__
  170. #define _MAX_PATH (PATH_MAX)
  171. #endif
  172. #if defined MAC || defined __MAC__ || defined linux
  173. int getAliasName(char *filename,char *newpath)
  174. {
  175. return 1;
  176. }
  177. #endif
  178. #ifndef min
  179. #define min(a,b) (((a) < (b)) ? (a) : (b) )
  180. #endif
  181. typedef unsigned short WORD;
  182. #if defined CDPLONG64 || defined unix
  183. typedef unsigned int DWORD;
  184. #else
  185. /* WIN32, so 4 bytes anyway */
  186. typedef unsigned long DWORD;
  187. #endif
  188. #ifdef NOTDEF
  189. // moved to sffuncs.h
  190. # define MSBFIRST (1)
  191. # define LSBFIRST (1)
  192. /*RWD May 2007: revise defines to recognise both forms of MAC (__PPC__) */
  193. # if defined(__I86__) || defined(_X86_) || defined(__i386__) || defined(__i486__) || defined(_IBMR2) || defined(__LITTLE_ENDIAN__)
  194. # undef MSBFIRST
  195. # elif defined(M68000) || defined(__sgi) || defined (__ppc__) || defined(__BIG_ENDIAN__)
  196. # undef LSBFIRST
  197. # else
  198. # error "Unknown byte order for this processor"
  199. # endif
  200. #if defined(MSBFIRST) && defined(LSBFIRST)
  201. #error "Internal: can't be both MSB and LSB"
  202. #endif
  203. #define REVDWBYTES(t) ( (((t)&0xff) << 24) | (((t)&0xff00) << 8) | (((t)&0xff0000) >> 8) | (((t)>>24) & 0xff) )
  204. #define REVWBYTES(t) ( (((t)&0xff) << 8) | (((t)>>8) &0xff) )
  205. /*RWD.6.99 REV3BYTES is a function*/
  206. static char * REV3BYTES(char *samp_24);
  207. extern int sampsize[];
  208. #ifdef MSBFIRST
  209. #define REVDATAINFILE(f) ((f)->filetype == riffwav || (f)->filetype == wave_ex)
  210. #else
  211. #define REVDATAINFILE(f) (((f)->filetype == eaaiff) || ((f)->filetype==aiffc))
  212. #endif
  213. #endif
  214. /*
  215. * Sfsys-related definitions
  216. */
  217. #define SFDBASE (1000)
  218. #define ALLOC(s) ((s *)malloc(sizeof(s)))
  219. #define TAG(a,b,c,d) ( ((a)<<24) | ((b)<<16) | ((c)<<8) | (d) )
  220. /*
  221. * Wave format-specific stuff
  222. */
  223. #ifndef WAVE_FORMAT_PCM
  224. #define WAVE_FORMAT_PCM (0x0001)
  225. #endif
  226. #ifndef WAVE_FORMAT_IEEE_FLOAT
  227. #define WAVE_FORMAT_IEEE_FLOAT (0x0003)
  228. #endif
  229. #ifndef WAVE_FORMAT_EXTENSIBLE
  230. #define WAVE_FORMAT_EXTENSIBLE (65534)
  231. #endif
  232. #define CURRENT_PEAK_VERSION (1)
  233. #define sizeof_WFMTEX (40)
  234. //#ifdef linux
  235. #ifdef __GLIBC__
  236. #define POS64(x) (x.__pos)
  237. #else
  238. #define POS64(x) (x)
  239. #endif
  240. typedef union {
  241. DWORD lsamp;
  242. float fsamp;
  243. unsigned char bytes[4];
  244. } SND_SAMP;
  245. struct fmtchunk {
  246. WORD formattag;
  247. WORD channels;
  248. DWORD samplespersec;
  249. DWORD avgbytespersec;
  250. WORD blockalign;
  251. };
  252. #if 0
  253. // now use wavdefs.h
  254. # ifndef _WIN32
  255. typedef struct _GUID
  256. {
  257. DWORD Data1;
  258. WORD Data2;
  259. WORD Data3;
  260. unsigned char Data4[8];
  261. } GUID;
  262. typedef struct {
  263. WORD wFormatTag;
  264. WORD nChannels;
  265. DWORD nSamplesPerSec;
  266. DWORD nAvgBytesPerSec;
  267. WORD nBlockAlign;
  268. WORD wBitsPerSample;
  269. WORD cbSize;
  270. } WAVEFORMATEX;
  271. # endif
  272. #endif
  273. // RWD TO TEST: on PC/MinGW: this need to be ifndef _WIN32 (or could just be ifndef WAVEFORMATEXTENSIBLE ?)
  274. #if 0
  275. typedef struct {
  276. WAVEFORMATEX Format;
  277. union {
  278. WORD wValidBitsPerSample; /* bits of precision */
  279. WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */
  280. WORD wReserved; /* If neither applies, set to */
  281. /* zero. */
  282. } Samples;
  283. DWORD dwChannelMask; /* which channels are */
  284. /* present in stream */
  285. GUID SubFormat;
  286. } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
  287. #endif
  288. // RWD For WIN32, link with ksuser.dll
  289. const /* static */ GUID KSDATAFORMAT_SUBTYPE_PCM = {0x00000001,0x0000,0x0010,
  290. {0x80,
  291. 0x00,
  292. 0x00,
  293. 0xaa,
  294. 0x00,
  295. 0x38,
  296. 0x9b,
  297. 0x71}};
  298. const /* static */ GUID KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003,0x0000,0x0010,
  299. {0x80,
  300. 0x00,
  301. 0x00,
  302. 0xaa,
  303. 0x00,
  304. 0x38,
  305. 0x9b,
  306. 0x71}};
  307. //B-FORMAT!
  308. // {00000001-0721-11d3-8644-C8C1CA000000}
  309. static const GUID SUBTYPE_AMBISONIC_B_FORMAT_PCM = { 0x00000001, 0x0721, 0x11d3,
  310. { 0x86,
  311. 0x44,
  312. 0xc8,
  313. 0xc1,
  314. 0xca,
  315. 0x0,
  316. 0x0,
  317. 0x0 } };
  318. static const GUID SUBTYPE_AMBISONIC_B_FORMAT_IEEE_FLOAT = { 0x00000003, 0x0721, 0x11d3,
  319. { 0x86,
  320. 0x44,
  321. 0xc8,
  322. 0xc1,
  323. 0xca,
  324. 0x0,
  325. 0x0,
  326. 0x0 } };
  327. struct cuepoint {
  328. DWORD name;
  329. DWORD position;
  330. DWORD incchunkid;
  331. DWORD chunkoffset;
  332. DWORD blockstart;
  333. DWORD sampleoffset;
  334. };
  335. /*
  336. * aiff format-specific stuff
  337. */
  338. struct aiffchunk {
  339. DWORD tag;
  340. DWORD size;
  341. fpos_t offset;
  342. char *buf;
  343. struct aiffchunk *next;
  344. };
  345. /*
  346. * Property storage structures
  347. */
  348. #define PROPCNKSIZE (2000)
  349. struct property {
  350. char *name;
  351. char *data;
  352. int size;
  353. struct property *next;
  354. };
  355. /*
  356. * Common declarations
  357. */
  358. enum sndfiletype {
  359. unknown_wave,
  360. riffwav,
  361. eaaiff,
  362. aiffc, //RWD sfsys98
  363. wave_ex, //RWD.5.99
  364. #ifdef ENABLE_PVX
  365. pvxfile,
  366. #endif
  367. cdpfile //RWD sfsys98
  368. };
  369. #ifdef ENABLE_PVX
  370. # include "pvfileio.h"
  371. #endif
  372. //RWD.6.99 NOTE: because of the slight possibility of 32bit int formats, from both file formats,
  373. // we need an explicit indicator of sample type. We choose to use the fmtchunk.formattag WAVE-style
  374. //for this, even for AIFF formats. Eventually, AIF-C will be used for all float AIFF files
  375. struct sf_file {
  376. char *filename;
  377. enum sndfiletype filetype;
  378. int refcnt;
  379. #if defined _WIN32
  380. HANDLE fileno;
  381. #else
  382. FILE* fileno;
  383. #endif
  384. int infochanged;
  385. int todelete;
  386. int readonly;
  387. DWORD mainchunksize;
  388. fpos_t fmtchunkoffset;
  389. WAVEFORMATEXTENSIBLE fmtchunkEx; //RWD NB: (for pvocex) includes WAVEFORMATEX as 'Format'
  390. int bitmask;
  391. fpos_t datachunkoffset;
  392. /* typedef from long long */
  393. __int64 datachunksize;
  394. __int64 sizerequested;
  395. int extrachunksizes;
  396. struct aiffchunk *aiffchunks;
  397. int proplim;
  398. fpos_t propoffset;
  399. int propschanged;
  400. int curpropsize;
  401. struct property *props;
  402. #ifdef ENABLE_PVX
  403. PVOCDATA *pvxprops;
  404. int pvxfileno;
  405. #endif
  406. DWORD curpos;
  407. fpos_t factchunkoffset;
  408. int header_set; //streaming: disallow header updates
  409. int is_shortcut;
  410. //RWD.6.5.99
  411. time_t peaktime;
  412. fpos_t peakchunkoffset;
  413. CHPEAK *peaks;
  414. channelformat chformat;
  415. int min_header;
  416. };
  417. /*
  418. * for later!!
  419. * I think all we have to do is keep an fd open for each file open, and share
  420. * the other information - we don't have to worry about being thread-safe, etc!!!
  421. */
  422. struct sf_openfile {
  423. struct sf_file *file;
  424. #if defined _WIN32
  425. HANDLE fileno;
  426. #else
  427. FILE* fileno;
  428. #endif
  429. DWORD curpos;
  430. };
  431. /*
  432. * Values for sizerequested
  433. */
  434. #define ES_EXIST (-2)
  435. #define LEAVESPACE (10*1024) /* file space that must be left */ //RWD? align to cluster size?
  436. /*
  437. * internal state
  438. */
  439. int rsferrno = 0;
  440. char *rsferrstr = "no previous error";
  441. static struct sf_file *findfile(int sfd);
  442. static struct sf_file *sf_files[SF_MAXFILES];
  443. //static enum sndfiletype gettypefromname(const char *path); //RWD98: lets declare this here
  444. static enum sndfiletype gettypefromname98(const char *path);
  445. static enum sndfiletype gettypefromfile(struct sf_file *f);
  446. static int wrwavhdr98(struct sf_file *f, int channels, int srate, int stype);
  447. static int wraiffhdr98(struct sf_file *f, int channels, int srate, int stype);
  448. static int wavupdate98(time_t thistime,struct sf_file *f);
  449. static int aiffupdate(time_t thistime,struct sf_file *f);
  450. static int aiffupdate98(time_t thistime,struct sf_file *f);
  451. //private, but used by snd routines
  452. unsigned int _rsf_getmaxpeak(int sfd,float *peak);
  453. /*RWD 3:2000 to add analysis properties internally */
  454. static int addprop(struct sf_file *f, char *propname, char *src, int size);
  455. #ifdef ENABLE_PVX
  456. static int writefirstprop(struct sf_file *f, char *propname, char *src, int size);
  457. static int pvx_createprops(struct sf_file *f);
  458. #endif
  459. static int compare_guids(const GUID *gleft, const GUID *gright)
  460. {
  461. const char *left = (const char *) gleft, *right = (const char *) gright;
  462. return !memcmp(left,right,sizeof(GUID));
  463. }
  464. static int file_exists(const char * fname);
  465. static int check_guid(struct sf_file *f)
  466. {
  467. //expects a GUID to be loaded already,
  468. //at present, we only need to know if this is b-format or not.
  469. //but might as well validate floatsam format against nBits , jic
  470. if(f->filetype != wave_ex) //should be an assert, but this is NOT a console lib!
  471. return 1;
  472. f->chformat = MC_STD;
  473. //we elabotate on possible std assignments later...
  474. if(compare_guids(&(f->fmtchunkEx.SubFormat),&(KSDATAFORMAT_SUBTYPE_PCM)))
  475. return 0;
  476. if(compare_guids(&(f->fmtchunkEx.SubFormat),&(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
  477. if(f->fmtchunkEx.Format.wBitsPerSample == 32)
  478. return 0;
  479. if(compare_guids(&(f->fmtchunkEx.SubFormat),&(SUBTYPE_AMBISONIC_B_FORMAT_PCM))) {
  480. f->chformat = MC_BFMT;
  481. return 0;
  482. }
  483. if(compare_guids(&(f->fmtchunkEx.SubFormat),&(SUBTYPE_AMBISONIC_B_FORMAT_IEEE_FLOAT))) {
  484. if(f->fmtchunkEx.Format.wBitsPerSample == 32){
  485. f->chformat = MC_BFMT;
  486. return 0;
  487. }
  488. }
  489. return 1;
  490. }
  491. /* RWD note: if not Windows, we use std C ftruncate() */
  492. #if defined _WIN32
  493. static int w_ch_size(HANDLE fh,__int64 size)
  494. {
  495. //#ifdef FILE64_WIN
  496. LARGE_INTEGER li;
  497. li.QuadPart = size;
  498. li.LowPart = SetFilePointer(fh,li.LowPart,&li.HighPart,FILE_BEGIN);
  499. if(li.LowPart != 0xFFFFFFFF && GetLastError() == NO_ERROR){
  500. if (!SetEndOfFile(fh))
  501. return -1;
  502. }
  503. else
  504. return -1;
  505. // #else
  506. // if(SetFilePointer(fh,(long) size,NULL,FILE_BEGIN)== 0xFFFFFFFF
  507. // || !SetEndOfFile(fh))
  508. // return -1;
  509. // #endif
  510. return 0;
  511. }
  512. #endif
  513. /*
  514. * read/write routines
  515. */
  516. /* RWD 2007 executive decision not to allow cnt >= 2GB! */
  517. #if defined _WIN32
  518. static __inline int
  519. doread(struct sf_file *f, char *buf, int cnt)
  520. {
  521. DWORD done = 0, count = (DWORD) cnt;
  522. if(f->fileno == INVALID_HANDLE_VALUE)
  523. return 1;
  524. if(!ReadFile(f->fileno, buf, count,&done,NULL)){
  525. # ifdef _DEBUG
  526. LPVOID lpMsgBuf;
  527. FormatMessage(
  528. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  529. NULL,
  530. GetLastError(),
  531. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
  532. (LPTSTR) &lpMsgBuf,
  533. 0,
  534. NULL
  535. );
  536. # ifndef WINDOWS
  537. fprintf(stderr,(const char *)lpMsgBuf);
  538. # else
  539. MessageBox( NULL, lpMsgBuf, "GetLastError", MB_OK|MB_ICONINFORMATION );
  540. # endif
  541. LocalFree( lpMsgBuf );
  542. # endif
  543. return 1;
  544. }
  545. return done != count;
  546. }
  547. #else
  548. //RWD NB returns ERROR if requested byte-count not read
  549. static __inline int
  550. doread(struct sf_file *f, char *buf, int cnt)
  551. {
  552. int done = fread(buf,sizeof(char),cnt,f->fileno);
  553. return done != cnt;
  554. }
  555. #endif
  556. /* RWD 31/11/23 : ~msf funcs used to read char strings (TAG name in Aiff/WAVE), lsf to read numbers */
  557. static int
  558. read_w_lsf(WORD *wp, struct sf_file *f)
  559. {
  560. WORD w;
  561. if(doread(f, (char *)&w, sizeof(WORD)))
  562. return 1;
  563. //#ifdef MSBFIRST
  564. // *wp = REVWBYTES(w);
  565. //#else
  566. *wp = w;
  567. //#endif
  568. return 0;
  569. }
  570. static int
  571. read_w_msf(WORD *wp, struct sf_file *f)
  572. {
  573. WORD w;
  574. if(doread(f, (char *)&w, sizeof(WORD)))
  575. return 1;
  576. //#ifdef LSBFIRST
  577. *wp = REVWBYTES(w);
  578. //#else
  579. // *wp = w;
  580. //#endif
  581. return 0;
  582. }
  583. static int
  584. read_dw_lsf(DWORD *dwp, struct sf_file *f)
  585. {
  586. DWORD dw;
  587. if(doread(f, (char *)&dw, sizeof(DWORD)))
  588. return 1;
  589. //#ifdef MSBFIRST
  590. // *dwp = REVDWBYTES(dw);
  591. //#else
  592. *dwp = dw;
  593. //#endif
  594. return 0;
  595. }
  596. static int
  597. read_dw_msf(DWORD *dwp, struct sf_file *f)
  598. {
  599. DWORD dw;
  600. if(doread(f, (char *)&dw, sizeof(DWORD)))
  601. return 1;
  602. //#ifdef LSBFIRST
  603. *dwp = REVDWBYTES(dw);
  604. //#else
  605. // *dwp = dw;
  606. //#endif
  607. return 0;
  608. }
  609. #if defined _WIN32
  610. static __inline int
  611. dowrite(struct sf_file *f, char *buf, int cnt)
  612. {
  613. DWORD done = 0, count = (DWORD)cnt;
  614. if(!WriteFile(f->fileno, buf, count,&done,NULL))
  615. return 1;
  616. return done != count;
  617. }
  618. #else
  619. static __inline int
  620. dowrite(struct sf_file *f, char *buf, int cnt)
  621. {
  622. int done = fwrite(buf,sizeof(char),cnt,f->fileno);
  623. return done != cnt;
  624. }
  625. #endif
  626. static int
  627. write_w_lsf(WORD w, struct sf_file *f)
  628. {
  629. //#ifdef MSBFIRST
  630. // w = REVWBYTES(w);
  631. //#endif
  632. return dowrite(f, (char *)&w, sizeof(WORD));
  633. }
  634. static int
  635. write_w_msf(WORD w, struct sf_file *f)
  636. {
  637. //#ifdef LSBFIRST
  638. w = REVWBYTES(w);
  639. //#endif
  640. return dowrite(f, (char *)&w, sizeof(WORD));
  641. }
  642. static int
  643. write_dw_lsf(DWORD dw, struct sf_file *f)
  644. {
  645. //#ifdef MSBFIRST
  646. // dw = REVDWBYTES(dw);
  647. //#endif
  648. return dowrite(f, (char *)&dw, sizeof(DWORD));
  649. }
  650. static int
  651. write_dw_msf(DWORD dw, struct sf_file *f)
  652. {
  653. //#ifdef LSBFIRST
  654. dw = REVDWBYTES(dw);
  655. //#endif
  656. return dowrite(f, (char *)&dw, sizeof(DWORD));
  657. }
  658. //RWD.6.5.99 write peak data
  659. /* NB position values are of frames, so int good for 2GB anyway */
  660. static int write_peak_lsf(int channels, struct sf_file *f)
  661. {
  662. int i;
  663. DWORD peak[2];
  664. SND_SAMP ssamp;
  665. #ifdef _DEBUG
  666. if(f->peaks==NULL){
  667. printf("\nerror: attempt to write uninitialized peak data");
  668. return 1;
  669. }
  670. #endif
  671. for(i=0; i < channels; i++){
  672. // /*long*/ DWORD *pdw;
  673. // pdw = (/*long*/DWORD *) &(f->peaks[i].value); /* RWD replaced with union */
  674. ssamp.fsamp = f->peaks[i].value;
  675. //peak[0] = *pdw;
  676. peak[0] = ssamp.lsamp;
  677. peak[1] = f->peaks[i].position;
  678. //#ifdef MSBFIRST
  679. // peak[0] = REVDWBYTES(peak[0]);
  680. // peak[1] = REVDWBYTES(peak[1]);
  681. //#endif
  682. if(dowrite(f,(char *) peak, 2 * sizeof(DWORD)))
  683. return 1;
  684. }
  685. return 0;
  686. }
  687. static int read_peak_lsf(int channels, struct sf_file *f)
  688. {
  689. int i;
  690. DWORD peak[2];
  691. SND_SAMP ssamp;
  692. #ifdef _DEBUG
  693. if(f->peaks==NULL){
  694. printf("\nerror: attempt to write uninitialized peak data");
  695. return 1;
  696. }
  697. #endif
  698. for(i=0;i < channels; i++){
  699. if(doread(f,(char *)peak,2 * sizeof(DWORD)))
  700. return 1;
  701. //#ifdef MSBFIRST
  702. // peak[0] = REVDWBYTES(peak[0]);
  703. // peak[1] = REVDWBYTES(peak[1]);
  704. //#endif
  705. ssamp.lsamp = peak[0];
  706. //f->peaks[i].value = *(float *) &(peak[0]); /* RWD TODO: replaced with union */
  707. f->peaks[i].value = ssamp.fsamp;
  708. f->peaks[i].position = peak[1];
  709. }
  710. return 0;
  711. }
  712. static int write_peak_msf(int channels, struct sf_file *f)
  713. {
  714. int i;
  715. DWORD peak[2];
  716. SND_SAMP ssamp;
  717. for(i=0; i < channels; i++){
  718. // /*long*/DWORD *pdw;
  719. //pdw = (/*long*/DWORD *) &(f->peaks[i].value); /* RWD replaced with union */
  720. ssamp.fsamp = f->peaks[i].value;
  721. // peak[0] = *pdw;
  722. peak[0] = ssamp.lsamp;
  723. peak[1] = f->peaks[i].position;
  724. //#ifdef LSBFIRST
  725. peak[0] = REVDWBYTES(peak[0]);
  726. peak[1] = REVDWBYTES(peak[1]);
  727. //#endif
  728. if(dowrite(f,(char *) peak, 2 * sizeof(DWORD)))
  729. return 1;
  730. }
  731. return 0;
  732. }
  733. static int read_peak_msf(int channels, struct sf_file *f)
  734. {
  735. int i;
  736. DWORD peak[2];
  737. SND_SAMP ssamp;
  738. for(i=0;i < channels; i++){
  739. if(doread(f,(char *)peak,2 * sizeof(DWORD)))
  740. return 1;
  741. //#ifdef LSBFIRST
  742. peak[0] = REVDWBYTES(peak[0]);
  743. peak[1] = REVDWBYTES(peak[1]);
  744. //#endif
  745. ssamp.lsamp = peak[0];
  746. //f->peaks[i].value = *(float *) &(peak[0]); /* RWD replaced with union */
  747. f->peaks[i].value = ssamp.fsamp;
  748. f->peaks[i].position = peak[1];
  749. }
  750. return 0;
  751. }
  752. /*
  753. * Fudge Apple extended format, for sample rates
  754. */
  755. /* RWD Oct 2022 removed old "TABLE_IEEE754" code */
  756. /* now using compact Csound code */
  757. #ifdef DW_EX_OLDCODE
  758. static int
  759. read_ex_todw(DWORD *dwp, struct sf_file *f)
  760. {
  761. double neg = 1.0;
  762. WORD exp;
  763. /*unsigned long*/DWORD ms_sig;
  764. double res;
  765. char buf[10]; /* for 80-bit extended float */
  766. if(doread(f, buf, 10))
  767. return 1;
  768. # ifdef LSBFIRST
  769. exp = REVWBYTES(*(WORD *)&buf[0]);
  770. ms_sig = (/*unsigned long*/DWORD)REVDWBYTES(*(DWORD *)&buf[2]); /* RWD TODO replace with union */
  771. # else
  772. exp = *(WORD *)&buf[0];
  773. ms_sig = (/*unsigned long*/DWORD)*(DWORD *)&buf[2]; /* RWD TODO replace with union */
  774. # endif
  775. if(exp & 0x8000) {
  776. exp &= ~0x8000;
  777. neg = -1.0;
  778. }
  779. exp -= 16382;
  780. res = (double)ms_sig/TWOPOW32;
  781. res = neg*ldexp(res, exp);
  782. *dwp = (DWORD)(res+0.5);
  783. return 0;
  784. }
  785. static int
  786. write_dw_toex(DWORD dw, struct sf_file *f)
  787. {
  788. double val = (double)dw;
  789. int neg = 0;
  790. /*unsigned long*/DWORD mant;
  791. int exp;
  792. char buf[10];
  793. if(val < 0.0) {
  794. val = -val;
  795. neg++;
  796. }
  797. mant = (/*unsigned long*/DWORD)(frexp(val, &exp) * TWOPOW32 + 0.5);
  798. exp += 16382;
  799. if(neg)
  800. exp |= 0x8000;
  801. # ifdef LSBFIRST
  802. *(WORD *)&buf[0] = REVWBYTES(exp); /* RWD TODO replace all with union? */
  803. *(DWORD *)&buf[2] = REVDWBYTES((DWORD)mant);
  804. # else
  805. *(WORD *)&buf[0] = exp;
  806. *(DWORD *)&buf[2] = mant;
  807. # endif
  808. *(DWORD *)&buf[6] = 0;
  809. return dowrite(f, buf, 10);
  810. }
  811. #else
  812. /* use Csound funcs */
  813. static int
  814. read_ex_todw(DWORD *dwp, struct sf_file *f)
  815. {
  816. double Csound_res = 0.0;
  817. char buf[10]; /* for 80-bit extended float */
  818. if(doread(f, buf, 10))
  819. return 1;
  820. Csound_res = ieee_80_to_double((unsigned char *) buf);
  821. *dwp = (DWORD) Csound_res;
  822. return 0;
  823. }
  824. static int
  825. write_dw_toex(DWORD dw, struct sf_file *f)
  826. {
  827. double val = (double)dw;
  828. char buf[10];
  829. double_to_ieee_80(val,(unsigned char *) buf);
  830. return dowrite(f,buf,10);
  831. }
  832. #endif // DW_EX_OLDCODE
  833. /*
  834. * wave file-format specific routines
  835. */
  836. static int
  837. getsfsyscue(struct sf_file *f)
  838. {
  839. DWORD cnt;
  840. int rc = 0;
  841. struct cuepoint cue;
  842. if(read_dw_lsf(&cnt, f))
  843. return -1;
  844. while(cnt-- > 0) {
  845. if(read_dw_msf(&cue.name, f)
  846. ||read_dw_lsf(&cue.position, f)
  847. ||read_dw_msf(&cue.incchunkid, f)
  848. ||read_dw_lsf(&cue.chunkoffset, f)
  849. ||read_dw_lsf(&cue.blockstart, f)
  850. ||read_dw_lsf(&cue.sampleoffset, f))
  851. return -1;
  852. if(cue.name == TAG('s','f','i','f'))
  853. rc = 1;
  854. }
  855. return rc;
  856. }
  857. /*
  858. * extended properties are as follows:
  859. *
  860. * property name '\n'
  861. * property value '\n'
  862. * ...
  863. * '\n'
  864. */
  865. static int
  866. xtoi(int ch)
  867. {
  868. if(ch >= '0' && ch <= '9')
  869. return ch - '0';
  870. if(ch >= 'A' && ch <= 'F')
  871. return ch - 'A' + 10;
  872. if(ch >= 'a' && ch <= 'f')
  873. return ch - 'a' + 10;
  874. return 0;
  875. }
  876. static int
  877. itox(int i)
  878. {
  879. static char trans[] = "0123456789ABCDEF";
  880. return trans[i&0x0f];
  881. }
  882. static void
  883. parseprops(struct sf_file *f, char *data)
  884. {
  885. char *cp = data;
  886. char *ep, *evp;
  887. int cnt;
  888. struct property **ppp = &f->props;
  889. struct property *np;
  890. f->curpropsize = 0;
  891. while(cp-data < f->proplim && *cp != '\n') {
  892. if((ep = strchr(cp, '\n')) == 0
  893. ||(evp = strchr(ep+1, '\n')) == 0
  894. ||((evp-ep-1)&1))
  895. return;
  896. if((np = ALLOC(struct property)) == 0
  897. ||(np->name = (char *) malloc(ep-cp+1)) == 0
  898. ||(np->data = (char *) malloc((evp-ep-1)/2)) == 0)
  899. return;
  900. np->size = (evp-ep-1)/2;
  901. np->next = 0;
  902. memcpy(np->name, cp, ep-cp);
  903. np->name[ep-cp] = '\0';
  904. for(cnt = 0; cnt < np->size; cnt++)
  905. np->data[cnt] = (xtoi((ep+1)[2*cnt])<<4) + xtoi((ep+1)[2*cnt+1]);
  906. *ppp = np;
  907. ppp = &np->next;
  908. f->curpropsize += strlen(np->name) + 1 + np->size + 1;
  909. cp = evp+1;
  910. }
  911. }
  912. static int
  913. writeprops(struct sf_file *f)
  914. {
  915. char *obuf, *op;
  916. int cnt;
  917. struct property *p = f->props;
  918. if((obuf = (char *) malloc(f->proplim)) == 0) {
  919. rsferrno = ESFNOMEM;
  920. rsferrstr = "No memory to write properties with";
  921. return -1;
  922. }
  923. op = obuf;
  924. while(p != 0) {
  925. strcpy(op, p->name);
  926. op += strlen(p->name);
  927. *op++ = '\n';
  928. for(cnt = 0; cnt < p->size; cnt++) {
  929. *op++ = itox(p->data[cnt]>>4);
  930. *op++ = itox(p->data[cnt]);
  931. }
  932. *op++ = '\n';
  933. if(op-obuf >= f->proplim) //RWD.1.99 this is really an assert test...
  934. abort();
  935. p = p->next;
  936. }
  937. while(op < &obuf[f->proplim])
  938. *op++ = '\n';
  939. /*RWD 2007: we rely on all props being within first 2GB of file! */
  940. #if defined _WIN32
  941. if (SetFilePointer(f->fileno,(LONG)f->propoffset,NULL,FILE_BEGIN) == 0xFFFFFFFF
  942. #else
  943. if(fseeko(f->fileno, POS64(f->propoffset), SEEK_SET)
  944. #endif
  945. ||dowrite(f, obuf, f->proplim)) {
  946. rsferrno = ESFWRERR;
  947. rsferrstr = "Write error writing new property values";
  948. return -1;
  949. }
  950. free(obuf);
  951. return 0;
  952. }
  953. static int
  954. getsfsysadtl(struct sf_file *f, int adtllen)
  955. {
  956. DWORD tag, size;
  957. DWORD name;
  958. fpos_t bytepos;
  959. char *propspace;
  960. char buf[1];
  961. while(adtllen > 0) {
  962. if(read_dw_msf(&tag, f)
  963. ||read_dw_lsf(&size, f))
  964. return -1;
  965. switch(tag) {
  966. case TAG('n','o','t','e'):
  967. if(read_dw_msf(&name, f))
  968. return -1;
  969. if(name != TAG('s','f','i','f')
  970. ||(int)(POS64(f->propoffset)) >= 0
  971. ||(propspace = (char *) malloc(size-sizeof(DWORD))) == 0) {
  972. #if defined _WIN32
  973. if(SetFilePointer(f->fileno,(LONG)((size-sizeof(DWORD)+1)&~1),NULL,FILE_CURRENT)== 0xFFFFFFFF)
  974. #else
  975. if(fseek(f->fileno, (size-sizeof(DWORD)+1)&~1, SEEK_CUR))
  976. #endif
  977. return -1;
  978. break;
  979. }
  980. f->proplim = size-sizeof(DWORD);
  981. #if defined _WIN32
  982. if((f->propoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF
  983. ||doread(f, propspace, size-sizeof(DWORD)))
  984. return -1;
  985. #else
  986. if(fgetpos(f->fileno,&bytepos)
  987. ||doread(f, propspace, size-sizeof(DWORD)))
  988. return -1;
  989. f->propoffset = bytepos;
  990. #endif
  991. parseprops(f, propspace);
  992. free(propspace);
  993. if(size&1)
  994. doread(f, buf, 1);
  995. break;
  996. default:
  997. #if defined _WIN32
  998. if(SetFilePointer(f->fileno, (size+1)&~1,NULL,FILE_CURRENT) == 0xFFFFFFFF)
  999. return -1;
  1000. #else
  1001. if(fseek(f->fileno, (size+1)&~1, SEEK_CUR) < 0)
  1002. return -1;
  1003. #endif
  1004. break;
  1005. }
  1006. adtllen -= 2*sizeof(DWORD) + ((size+1)&~1); /* RWD Jan 2013 */
  1007. }
  1008. return 0;
  1009. }
  1010. //RWD.7.99 TODO: set f->min_header here?
  1011. /*RWD 2007: MUST use DWORD to enure we get sizes up to 4GB */
  1012. /* BUT: if we seek to end of data chunk, need 64bit seek */
  1013. static int
  1014. rdwavhdr(struct sf_file *f)
  1015. {
  1016. DWORD tag, size;
  1017. int fmtseen = 0;
  1018. int dataseen = 0; /*RWD April 2006: try to read PEAK chunk after data (boo hiss Sony! )*/
  1019. int err = 0; /* "" */
  1020. int gotsfsyscue = 0;
  1021. DWORD factsize = 0;
  1022. DWORD peak_version;
  1023. #if defined _WIN32
  1024. LARGE_INTEGER pos64; /* pos64.QuadPart is __int64 */
  1025. #endif
  1026. fpos_t bytepos;
  1027. //WAVEFORMATEXTENSIBLE *pFmtEx;
  1028. if(read_dw_msf(&tag, f)
  1029. ||read_dw_lsf(&size, f)
  1030. ||tag != TAG('R','I','F','F')) {
  1031. rsferrno = ESFNOTFOUND;
  1032. rsferrstr = "File is not a RIFF file";
  1033. return 1;
  1034. }
  1035. if(size < 4) {
  1036. rsferrno = ESFNOTFOUND;
  1037. rsferrstr = "File data size is too small";
  1038. return 1;
  1039. }
  1040. if(read_dw_msf(&tag, f)
  1041. ||tag != TAG('W','A','V','E')) {
  1042. rsferrno = ESFNOTFOUND;
  1043. rsferrstr = "File is not a wave RIFF file";
  1044. return 1;
  1045. }
  1046. f->filetype = riffwav; //might be wave_ex
  1047. f->mainchunksize = size;
  1048. f->extrachunksizes = 0;
  1049. f->proplim = 0;
  1050. f->props = 0;
  1051. POS64(f->propoffset) = (unsigned) -1;
  1052. POS64(f->factchunkoffset) = (unsigned) -1;
  1053. //datachunkoffset now initialized in allocsffile
  1054. //RWD.6.99 do I need to do the AIFF getout for bad sizes here too?
  1055. for(;;) {
  1056. if(read_dw_msf(&tag, f)
  1057. ||read_dw_lsf(&size,f)){
  1058. /*RWD April 2006 TODO: detect EOF! */
  1059. err++;
  1060. goto ioerror;
  1061. }
  1062. switch(tag) {
  1063. case TAG('f','m','t',' '):
  1064. //RWD: must deal with possibility of WAVEFORMATEX extra cbSize word
  1065. #if defined _WIN32
  1066. if((f->fmtchunkoffset = SetFilePointer(f->fileno, 0L,NULL, FILE_CURRENT))== 0xFFFFFFFF
  1067. ||read_w_lsf(&f->fmtchunkEx.Format.wFormatTag, f)
  1068. ||read_w_lsf(&f->fmtchunkEx.Format.nChannels, f)
  1069. ||read_dw_lsf(&f->fmtchunkEx.Format.nSamplesPerSec, f)
  1070. ||read_dw_lsf(&f->fmtchunkEx.Format.nAvgBytesPerSec, f)
  1071. ||read_w_lsf(&f->fmtchunkEx.Format.nBlockAlign, f) ) {
  1072. err++;
  1073. goto ioerror;
  1074. }
  1075. #else
  1076. if(fgetpos(f->fileno, &bytepos)
  1077. ||read_w_lsf(&f->fmtchunkEx.Format.wFormatTag, f)
  1078. ||read_w_lsf(&f->fmtchunkEx.Format.nChannels, f)
  1079. ||read_dw_lsf(&f->fmtchunkEx.Format.nSamplesPerSec, f)
  1080. ||read_dw_lsf(&f->fmtchunkEx.Format.nAvgBytesPerSec, f)
  1081. ||read_w_lsf(&f->fmtchunkEx.Format.nBlockAlign, f) ) {
  1082. err++;
  1083. goto ioerror;
  1084. }
  1085. f->fmtchunkoffset = bytepos;
  1086. #endif
  1087. switch(f->fmtchunkEx.Format.wFormatTag) {
  1088. case WAVE_FORMAT_PCM:
  1089. case WAVE_FORMAT_IEEE_FLOAT: //RWD 07:97
  1090. case WAVE_FORMAT_EXTENSIBLE: //RWD.5.99
  1091. if(read_w_lsf(&f->fmtchunkEx.Format.wBitsPerSample, f)) {
  1092. err++;
  1093. goto ioerror;
  1094. }
  1095. //RWD.6.99 set f->fmtchunkEx.Samples.wValidBitsPerSample to this as default
  1096. // will only be changed by a WAVE_EX header
  1097. f->fmtchunkEx.Samples.wValidBitsPerSample = f->fmtchunkEx.Format.wBitsPerSample;
  1098. //deal with things such as 20bits per sample...
  1099. //this covers standard WAVE, WAVE-EX may adjust again
  1100. if(f->fmtchunkEx.Format.wBitsPerSample !=
  1101. ((f->fmtchunkEx.Format.nBlockAlign / f->fmtchunkEx.Format.nChannels) * 8)){
  1102. //deduce the container size
  1103. f->fmtchunkEx.Format.wBitsPerSample =
  1104. ((f->fmtchunkEx.Format.nBlockAlign / f->fmtchunkEx.Format.nChannels) * 8);
  1105. }
  1106. switch(f->fmtchunkEx.Format.wBitsPerSample) {
  1107. case 32: /* floats or longs*/
  1108. break;
  1109. case(24):
  1110. case 16: /* shorts */
  1111. case 8: /* byte -> short mappping */
  1112. /*RWD 07:97*/ if(!(f->fmtchunkEx.Format.wFormatTag == WAVE_FORMAT_PCM ||
  1113. f->fmtchunkEx.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)){
  1114. rsferrno = ESFNOTFOUND;
  1115. rsferrstr = "can't open Sfile : Format mismatch";
  1116. return 1;
  1117. }
  1118. break;
  1119. default:
  1120. rsferrno = ESFNOTFOUND;
  1121. rsferrstr = "can't open Sfile - unsupported format";
  1122. return 1;
  1123. }
  1124. //now catch any extra bytes, and parse WAVE_EX if we have it...
  1125. if(size > 16){
  1126. unsigned short cbSize;
  1127. if(read_w_lsf(&cbSize,f))
  1128. goto ioerror;
  1129. /* RWD May 2011. Effing Steinberg Wavelab writes a 20byte fmt chunk! */
  1130. /* Feb 2012: AND Pro Tools writes a 40byte fmt chunk! */
  1131. if(cbSize==0){
  1132. int wordstoskip = (size-18) / sizeof(WORD);
  1133. int skip;
  1134. unsigned short dummy;
  1135. for(skip = 0; skip < wordstoskip; skip++){
  1136. if(read_w_lsf(&dummy,f))
  1137. goto ioerror;
  1138. }
  1139. }
  1140. else{
  1141. if(f->fmtchunkEx.Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE){
  1142. rsferrno = ESFNOTFOUND;
  1143. rsferrstr = "unexpected extra format information - not a wave file";
  1144. return 1;
  1145. }
  1146. if(cbSize != 22){
  1147. rsferrno = ESFNOTFOUND;
  1148. rsferrstr = "unexpected extra format information in WAVE_EX file!";
  1149. return 1;
  1150. }
  1151. f->filetype = wave_ex;
  1152. if(read_w_lsf(&(f->fmtchunkEx.Samples.wValidBitsPerSample),f)
  1153. ||
  1154. read_dw_lsf(&(f->fmtchunkEx.dwChannelMask),f)){
  1155. err++;
  1156. goto ioerror;
  1157. }
  1158. //get the GUID
  1159. if(doread(f,(char *) &(f->fmtchunkEx.SubFormat),sizeof(GUID))) {
  1160. err++;
  1161. goto ioerror;
  1162. }
  1163. #ifdef MSBFIRST
  1164. f->fmtchunkEx.SubFormat.Data1 = REVDWBYTES(f->fmtchunkEx.SubFormat.Data1);
  1165. f->fmtchunkEx.SubFormat.Data2 = REVWBYTES(f->fmtchunkEx.SubFormat.Data2);
  1166. f->fmtchunkEx.SubFormat.Data3 = REVWBYTES(f->fmtchunkEx.SubFormat.Data3);
  1167. #endif
  1168. if(check_guid(f)){
  1169. rsferrno = ESFNOTFOUND;
  1170. rsferrstr = "unrecognized WAV_EX subformat";
  1171. return 1;
  1172. }
  1173. //we don't try to ID the spkr-config here: do that in the sf/snd open fucntions
  1174. }
  1175. }
  1176. break;
  1177. default:
  1178. rsferrno = ESFNOTFOUND;
  1179. rsferrstr = "can't open Sfile - unsupported format";
  1180. return 1;
  1181. }
  1182. //set the bitmask here - covers plain WAVE too
  1183. if(f->fmtchunkEx.Samples.wValidBitsPerSample
  1184. < f->fmtchunkEx.Format.wBitsPerSample){
  1185. int mask = 0xffffffff;
  1186. int shift = 32 - f->fmtchunkEx.Format.wBitsPerSample;
  1187. f->bitmask = mask << (shift + (f->fmtchunkEx.Format.wBitsPerSample
  1188. - f->fmtchunkEx.Samples.wValidBitsPerSample));
  1189. }
  1190. fmtseen++;
  1191. break;
  1192. case TAG('L','I','S','T'):
  1193. if(read_dw_msf(&tag, f))
  1194. goto ioerror;
  1195. switch(tag) {
  1196. case TAG('w','a','v','l'):
  1197. rsferrno = ESFNOTFOUND;
  1198. rsferrstr = "Can't open SFfile - no support for list chunks yet!";
  1199. return 1;
  1200. case TAG('a','d','t','l'):
  1201. if(getsfsysadtl(f, size-sizeof(DWORD)) < 0) {
  1202. err++;
  1203. goto ioerror;
  1204. }
  1205. break;
  1206. default:
  1207. #if defined _WIN32
  1208. if(SetFilePointer(f->fileno, size-sizeof(DWORD),NULL, FILE_CURRENT) == 0xFFFFFFFF)
  1209. #else
  1210. POS64(bytepos) = size-sizeof(DWORD);
  1211. if(fseeko(f->fileno, /*size-sizeof(DWORD)*/POS64(bytepos), SEEK_CUR) < 0)
  1212. #endif
  1213. {
  1214. err++;
  1215. goto ioerror;
  1216. }
  1217. break;
  1218. }
  1219. break;
  1220. //read fact chunk (not needed for std PCM files...but we use it anyway in sfsys97!
  1221. case TAG('f','a','c','t'):
  1222. #if defined _WIN32
  1223. if((f->factchunkoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF)
  1224. #else
  1225. if(fgetpos(f->fileno,&f->factchunkoffset))
  1226. #endif
  1227. {
  1228. err++;
  1229. goto ioerror;
  1230. }
  1231. if(read_dw_lsf(&factsize,f)) {
  1232. err++;
  1233. goto ioerror;
  1234. }
  1235. break; //RWD: need to update extrachunksizes?
  1236. //RWD.5.99 read PEAK chunk
  1237. case TAG('P','E','A','K'):
  1238. f->peaks = (CHPEAK *) calloc(f->fmtchunkEx.Format.nChannels,sizeof(CHPEAK));
  1239. if(f->peaks == NULL){
  1240. rsferrno = ESFNOMEM;
  1241. rsferrstr = "No memory for peak data";
  1242. return 1;
  1243. }
  1244. if(read_dw_lsf(&peak_version,f)) {
  1245. err++;
  1246. goto ioerror;
  1247. }
  1248. switch(peak_version){
  1249. case(CURRENT_PEAK_VERSION):
  1250. if(read_dw_lsf((DWORD*) &(f->peaktime),f)){
  1251. err++;
  1252. goto ioerror;
  1253. }
  1254. /* RWD 2007: PEAK chunk is after data chunk in some naff but otherwise legal files,
  1255. so ordinary lseek no good */
  1256. #if defined _WIN32
  1257. pos64.QuadPart = 0;
  1258. pos64.LowPart = SetFilePointer(f->fileno, 0L, &pos64.HighPart, FILE_CURRENT);
  1259. if(pos64.LowPart == 0xFFFFFFFF && GetLastError() != NO_ERROR){
  1260. err++;
  1261. goto ioerror;
  1262. }
  1263. else {
  1264. /* WAVE and AIFF have to fit inside unsigned int */
  1265. f->peakchunkoffset = (unsigned int) pos64.QuadPart;
  1266. if(read_peak_lsf(f->fmtchunkEx.Format.nChannels,f)) {
  1267. err++;
  1268. goto ioerror;
  1269. }
  1270. }
  1271. #else
  1272. if(fgetpos(f->fileno,&f->peakchunkoffset)
  1273. || read_peak_lsf(f->fmtchunkEx.Format.nChannels,f)) {
  1274. err++;
  1275. goto ioerror;
  1276. }
  1277. #endif
  1278. break;
  1279. default:
  1280. #ifdef _DEBUG
  1281. fprintf(stderr,"\nunknown PEAK version!");
  1282. #endif
  1283. free(f->peaks);
  1284. f->peaks = NULL;
  1285. break;
  1286. }
  1287. break;
  1288. case TAG('d','a','t','a'):
  1289. #if defined _WIN32
  1290. /* datachunk MUST be within 2GB! */
  1291. if((f->datachunkoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF){
  1292. err++;
  1293. goto ioerror;
  1294. }
  1295. f->datachunksize = size;
  1296. if(f->fmtchunkEx.Format.wBitsPerSample == 8)
  1297. f->datachunksize *= 2;
  1298. #else
  1299. if(fgetpos(f->fileno,&f->datachunkoffset) ){
  1300. err++;
  1301. goto ioerror;
  1302. }
  1303. f->datachunksize = size;
  1304. if(f->fmtchunkEx.Format.wBitsPerSample == 8)
  1305. f->datachunksize *= 2;
  1306. #endif
  1307. /* skip over data chunk; to try to read later chunks */
  1308. size = (size+1)&~1;
  1309. #if defined _WIN32
  1310. pos64.QuadPart = (__int64) size;
  1311. pos64.LowPart = SetFilePointer(f->fileno, pos64.LowPart,&pos64.HighPart,FILE_CURRENT);
  1312. if(pos64.LowPart == 0xFFFFFFFF && GetLastError() != NO_ERROR){
  1313. err++;
  1314. goto ioerror;
  1315. }
  1316. #else
  1317. /* expect >2GB data chunk, so must use fseeko etc */
  1318. POS64(bytepos) = POS64(f->datachunkoffset) + size;
  1319. if(fsetpos(f->fileno, &bytepos)) {
  1320. err++;
  1321. goto ioerror;
  1322. }
  1323. #endif
  1324. dataseen++;
  1325. break;
  1326. case TAG('c','u','e',' '):
  1327. if((gotsfsyscue = getsfsyscue(f)) < 0) {
  1328. err++;
  1329. goto ioerror;
  1330. }
  1331. break;
  1332. default:
  1333. size = (size+1)&~1;
  1334. /* we trust that only the data chunk will be huge! */
  1335. #if defined _WIN32
  1336. if(SetFilePointer(f->fileno, size, NULL,FILE_CURRENT) == 0xFFFFFFFF) {
  1337. err++;
  1338. goto ioerror;
  1339. }
  1340. #else
  1341. if(fseek(f->fileno, size, SEEK_CUR) < 0) {
  1342. err++;
  1343. goto ioerror;
  1344. }
  1345. #endif
  1346. f->extrachunksizes += size + 2*sizeof(DWORD); //RWD: anonymous chunks - we will copy these one day...
  1347. break;
  1348. }
  1349. }
  1350. /* NOTREACHED */
  1351. ioerror:
  1352. if(fmtseen && dataseen)
  1353. return 0;
  1354. rsferrno = ESFRDERR;
  1355. rsferrstr = "read error (or file too short) reading wav header";
  1356. return 1;
  1357. }
  1358. /********** SFSYS98 version ****************
  1359. * this RECEIVES format data from calling function,
  1360. * to create the required header
  1361. */
  1362. static int
  1363. wrwavhdr98(struct sf_file *f, int channels, int srate, int stype)
  1364. {
  1365. struct cuepoint cue;
  1366. int extra = 0;
  1367. int wordsize;
  1368. #ifdef linux
  1369. fpos_t bytepos = {0};
  1370. #else
  1371. fpos_t bytepos = 0;
  1372. #endif
  1373. WORD cbSize = 0x0000; //RWD for WAVEFORMATEX, FLOAT FORMAT ONLY
  1374. f->mainchunksize = 0; /* we don't know the full size yet! */
  1375. f->extrachunksizes = 0;
  1376. //we will not use sffuncs for 24bit files!
  1377. if(stype >= SAMP_MASKED){
  1378. rsferrstr = "this verson cannot write files in requested format";
  1379. return 1;
  1380. }
  1381. //wordsize = (stype == SAMP_FLOAT ? sizeof(float) : sizeof(short));
  1382. wordsize = sampsize[stype];
  1383. if(stype== SAMP_FLOAT)
  1384. extra = sizeof(WORD);
  1385. if(write_dw_msf(TAG('R','I','F','F'), f)
  1386. ||write_dw_lsf(0, f)
  1387. ||write_dw_msf(TAG('W','A','V','E'), f))
  1388. goto ioerror;
  1389. f->fmtchunkEx.Format.wFormatTag = stype == SAMP_FLOAT ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM;
  1390. f->fmtchunkEx.Format.nChannels = (unsigned short)channels;
  1391. f->fmtchunkEx.Format.nSamplesPerSec = srate;
  1392. f->fmtchunkEx.Format.nAvgBytesPerSec = wordsize * channels * srate;
  1393. f->fmtchunkEx.Format.nBlockAlign = (unsigned short) ( wordsize * channels);
  1394. //for standard WAVE, we set wBitsPerSample to = validbits
  1395. if(stype==SAMP_2024)
  1396. f->fmtchunkEx.Format.wBitsPerSample = 20;
  1397. else if(stype==SAMP_2432)
  1398. f->fmtchunkEx.Format.wBitsPerSample = 24;
  1399. else
  1400. f->fmtchunkEx.Format.wBitsPerSample = (short)(8 * wordsize);
  1401. //need this for wavupdate98()
  1402. f->fmtchunkEx.Samples.wValidBitsPerSample = f->fmtchunkEx.Format.wBitsPerSample;
  1403. if(write_dw_msf(TAG('f','m','t',' '), f)
  1404. ||write_dw_lsf(16 + extra, f) //RWD CDP97: size = 18 to include cbSize field
  1405. #if defined _WIN32
  1406. ||((f->fmtchunkoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF)
  1407. ||write_w_lsf(f->fmtchunkEx.Format.wFormatTag, f)
  1408. ||write_w_lsf(f->fmtchunkEx.Format.nChannels, f)
  1409. ||write_dw_lsf(f->fmtchunkEx.Format.nSamplesPerSec, f)
  1410. ||write_dw_lsf(f->fmtchunkEx.Format.nAvgBytesPerSec, f)
  1411. ||write_w_lsf(f->fmtchunkEx.Format.nBlockAlign, f)
  1412. ||write_w_lsf(f->fmtchunkEx.Format.wBitsPerSample, f)
  1413. )
  1414. goto ioerror;
  1415. #else
  1416. ||fgetpos(f->fileno,&bytepos)
  1417. ||write_w_lsf(f->fmtchunkEx.Format.wFormatTag, f)
  1418. ||write_w_lsf(f->fmtchunkEx.Format.nChannels, f)
  1419. ||write_dw_lsf(f->fmtchunkEx.Format.nSamplesPerSec, f)
  1420. ||write_dw_lsf(f->fmtchunkEx.Format.nAvgBytesPerSec, f)
  1421. ||write_w_lsf(f->fmtchunkEx.Format.nBlockAlign, f)
  1422. ||write_w_lsf(f->fmtchunkEx.Format.wBitsPerSample, f)
  1423. )
  1424. goto ioerror;
  1425. f->fmtchunkoffset = bytepos;
  1426. #endif
  1427. if(stype == SAMP_FLOAT) {
  1428. if(write_w_lsf(cbSize,f))
  1429. goto ioerror;
  1430. }
  1431. //RWD.6.5.99 ADD the PEAK chunk
  1432. if((f->min_header >= SFILE_PEAKONLY) && f->peaks){
  1433. int i,size;
  1434. DWORD now = 0;
  1435. for(i=0;i < channels; i++){
  1436. f->peaks[i].value = 0.0f;
  1437. f->peaks[i].position = 0;
  1438. }
  1439. size = 2 * sizeof(DWORD) + channels * sizeof(CHPEAK);
  1440. if(write_dw_msf(TAG('P','E','A','K'),f)
  1441. || write_dw_lsf(size,f)
  1442. #if defined _WIN32
  1443. || ((f->peakchunkoffset = SetFilePointer(f->fileno,0L,NULL, FILE_CURRENT))== 0xFFFFFFFF)
  1444. || write_dw_lsf(CURRENT_PEAK_VERSION,f)
  1445. || write_dw_lsf(now,f)
  1446. || write_peak_lsf(channels,f))
  1447. goto ioerror;
  1448. #else
  1449. || fgetpos(f->fileno,&bytepos)
  1450. || write_dw_lsf(CURRENT_PEAK_VERSION,f)
  1451. || write_dw_lsf(now,f)
  1452. || write_peak_lsf(channels,f))
  1453. goto ioerror;
  1454. f->peakchunkoffset = bytepos;
  1455. #endif
  1456. }
  1457. if(f->min_header >= SFILE_CDP){
  1458. /*
  1459. * add the cue point/note chunk for properties
  1460. */
  1461. /* RWD Nov 2009: don't need cue for analysis files */
  1462. if(f->min_header==SFILE_CDP){
  1463. //RWD TODO: add switch to skip writing this extra stuff!
  1464. if(write_dw_msf(TAG('c','u','e',' '), f)
  1465. ||write_dw_lsf(sizeof(struct cuepoint) + sizeof(DWORD), f) )
  1466. goto ioerror;
  1467. cue.name = TAG('s','f','i','f');
  1468. cue.position = 0;
  1469. cue.incchunkid = TAG('d','a','t','a');
  1470. cue.chunkoffset = 0;
  1471. cue.blockstart = 0;
  1472. cue.sampleoffset = 0;
  1473. if(write_dw_lsf(1, f) /* one cue point */
  1474. ||write_dw_msf(cue.name, f)
  1475. ||write_dw_lsf(cue.position, f)
  1476. ||write_dw_msf(cue.incchunkid, f)
  1477. ||write_dw_lsf(cue.chunkoffset, f)
  1478. ||write_dw_lsf(cue.blockstart, f)
  1479. ||write_dw_lsf(cue.sampleoffset, f) )
  1480. goto ioerror;
  1481. }
  1482. /*... add a LIST chunk of type 'adtl'... */
  1483. if(write_dw_msf(TAG('L','I','S','T'), f)
  1484. ||write_dw_lsf(sizeof(DWORD) + 3*sizeof(DWORD) + PROPCNKSIZE, f)
  1485. ||write_dw_msf(TAG('a','d','t','l'), f) )
  1486. goto ioerror;
  1487. /* add the property-space note chunk */
  1488. if(write_dw_msf(TAG('n','o','t','e'), f)
  1489. ||write_dw_lsf(sizeof(DWORD) + PROPCNKSIZE, f)
  1490. ||write_dw_msf(TAG('s','f','i','f'), f)
  1491. #if defined _WIN32
  1492. ||((f->propoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF)
  1493. ||SetFilePointer(f->fileno, (long)PROPCNKSIZE,NULL, FILE_CURRENT) == 0xFFFFFFFF )
  1494. goto ioerror;
  1495. #else
  1496. ||fgetpos(f->fileno, &bytepos)
  1497. ||fseek(f->fileno, (long)PROPCNKSIZE, SEEK_CUR) < 0)
  1498. goto ioerror;
  1499. f->propoffset = bytepos;
  1500. #endif
  1501. f->propschanged = 1;
  1502. f->proplim = PROPCNKSIZE;
  1503. }
  1504. /*
  1505. * and add the data chunk
  1506. */
  1507. f->datachunksize = 0;
  1508. if(write_dw_msf(TAG('d','a','t','a'), f)
  1509. ||write_dw_lsf(0, f)
  1510. #if defined _WIN32
  1511. ||((f->datachunkoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF))
  1512. goto ioerror;
  1513. #else
  1514. ||fgetpos(f->fileno, &bytepos))
  1515. goto ioerror;
  1516. f->datachunkoffset = bytepos;
  1517. #endif
  1518. f->header_set = 1; //later, may allow update prior to first write ?
  1519. return 0;
  1520. /* NOTREACHED */
  1521. ioerror:
  1522. rsferrno = ESFWRERR;
  1523. rsferrstr = "write error writing formatted wav header";
  1524. return 1;
  1525. }
  1526. //wave-ex special
  1527. static int
  1528. wrwavex(struct sf_file *f, SFPROPS *props)
  1529. {
  1530. struct cuepoint cue;
  1531. //int extra = 0;
  1532. int wordsize;
  1533. WORD validbits,cbSize = 22;
  1534. GUID guid;
  1535. GUID *pGuid = NULL;
  1536. //int fmtsize = sizeof_WFMTEX;
  1537. fpos_t bytepos;
  1538. POS64(bytepos) = 0;
  1539. f->mainchunksize = 0; /* we don't know the full size yet! */
  1540. f->extrachunksizes = 0;
  1541. POS64(f->propoffset) = 0;
  1542. if(props->chformat==STDWAVE){
  1543. rsferrno = ESFBADPARAM;
  1544. rsferrstr = "std wave format requested for WAVE-EX file!";
  1545. return 1;
  1546. }
  1547. if(props->samptype == FLOAT32){
  1548. pGuid = (GUID *) &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
  1549. }
  1550. else{
  1551. pGuid =(GUID *) &KSDATAFORMAT_SUBTYPE_PCM;
  1552. }
  1553. //NB AIFF and AIFF-C don't support masked formats - just write the required larger container size
  1554. switch(props->samptype){
  1555. case(INT_32):
  1556. case(FLOAT32):
  1557. case(INT2432):
  1558. wordsize = sizeof(/*long*/int);
  1559. break;
  1560. case(INT2424):
  1561. case(INT2024):
  1562. wordsize = 3;
  1563. break;
  1564. case(SHORT16):
  1565. wordsize= sizeof(short);
  1566. break;
  1567. default:
  1568. //don't accept SHORT8, can't deal with INT_MASKED yet - no info in SFPROPS yet!
  1569. rsferrno = ESFBADPARAM;
  1570. rsferrstr = "unsupported sample format requested for WAVE-EX file";
  1571. return 1;
  1572. }
  1573. if(props->samptype==INT2432)
  1574. validbits = (WORD)24;
  1575. else if(props->samptype==INT2024)
  1576. validbits = (WORD)20;
  1577. else
  1578. validbits = (WORD)( 8 * wordsize); //deal with more masks in due course...
  1579. if(write_dw_msf(TAG('R','I','F','F'), f)
  1580. ||write_dw_lsf(0, f)
  1581. ||write_dw_msf(TAG('W','A','V','E'), f))
  1582. goto ioerror;
  1583. /* MC_STD,MC_GENERIC,MC_LCRS,MC_BFMT,MC_DOLBY_5_1,
  1584. MC_SURR_5_0,MC_SURR_7_1,MC_CUBE,MC_WAVE_EX
  1585. */
  1586. f->fmtchunkEx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
  1587. f->fmtchunkEx.Format.nChannels = (unsigned short) props->chans;
  1588. f->fmtchunkEx.Format.nSamplesPerSec = props->srate;
  1589. f->fmtchunkEx.Format.nAvgBytesPerSec = wordsize * props->chans * props->srate;
  1590. f->fmtchunkEx.Format.nBlockAlign = (unsigned short) ( wordsize * props->chans);
  1591. f->fmtchunkEx.Format.wBitsPerSample = (WORD)(wordsize * 8);
  1592. f->fmtchunkEx.Samples.wValidBitsPerSample = validbits;
  1593. /*RWD Jan 30 2007: permit mask bits < nChans */
  1594. switch(props->chformat){
  1595. case(MC_STD):
  1596. f->fmtchunkEx.dwChannelMask = SPKRS_UNASSIGNED;
  1597. break;
  1598. case(MC_MONO):
  1599. if(props->chans /*!=*/ < 1){ /*RWD Jan 30 2007 */
  1600. rsferrno = ESFBADPARAM;
  1601. rsferrstr = "conflicting channel configuration for WAVE-EX file";
  1602. return 1;
  1603. }
  1604. f->fmtchunkEx.dwChannelMask = SPKRS_MONO;
  1605. break;
  1606. case(MC_STEREO):
  1607. if(props->chans /*!=*/ < 2){
  1608. rsferrno = ESFBADPARAM;
  1609. rsferrstr = "conflicting channel configuration for WAVE-EX file";
  1610. return 1;
  1611. }
  1612. f->fmtchunkEx.dwChannelMask = SPKRS_STEREO;
  1613. break;
  1614. case(MC_QUAD):
  1615. if(props->chans /*!=*/ < 4){
  1616. rsferrno = ESFBADPARAM;
  1617. rsferrstr = "conflicting channel configuration for WAVE-EX file";
  1618. return 1;
  1619. }
  1620. f->fmtchunkEx.dwChannelMask = SPKRS_GENERIC_QUAD;
  1621. break;
  1622. case(MC_BFMT):
  1623. // Nov 2005: now supporting many channel counts for B-Format!
  1624. #ifdef NOTDEF
  1625. if(props->chans != 4){
  1626. rsferrno = ESFBADPARAM;
  1627. rsferrstr = "conflicting channel configuration for WAVE-EX file";
  1628. return 1;
  1629. }
  1630. #endif
  1631. f->fmtchunkEx.dwChannelMask = SPKRS_UNASSIGNED;
  1632. pGuid = props->samptype==FLOAT32 ?(GUID *) &SUBTYPE_AMBISONIC_B_FORMAT_IEEE_FLOAT :(GUID *) &SUBTYPE_AMBISONIC_B_FORMAT_PCM;
  1633. break;
  1634. case(MC_LCRS):
  1635. if(props->chans /*!=*/< 4){
  1636. rsferrno = ESFBADPARAM;
  1637. rsferrstr = "conflicting channel configuration for WAVE-EX file";
  1638. return 1;
  1639. }
  1640. f->fmtchunkEx.dwChannelMask = SPKRS_SURROUND_LCRS;
  1641. break;
  1642. case(MC_DOLBY_5_1):
  1643. if(props->chans /*!=*/ < 6){
  1644. rsferrno = ESFBADPARAM;
  1645. rsferrstr = "conflicting channel configuration for WAVE-EX file";
  1646. return 1;
  1647. }
  1648. f->fmtchunkEx.dwChannelMask = SPKRS_DOLBY5_1;
  1649. break;
  1650. /*March 2008 */
  1651. case(MC_SURR_5_0):
  1652. if(props->chans /*!=*/ < 5){
  1653. rsferrno = ESFBADPARAM;
  1654. rsferrstr = "conflicting channel configuration for WAVE-EX file";
  1655. return 1;
  1656. }
  1657. f->fmtchunkEx.dwChannelMask = SPKRS_SURR_5_0;
  1658. break;
  1659. /* Nov 2013 */
  1660. case(MC_SURR_6_1):
  1661. if(props->chans < 7){
  1662. rsferrno = ESFBADPARAM;
  1663. rsferrstr = "conflicting channel configuration for WAVE-EX file";
  1664. return 1;
  1665. }
  1666. f->fmtchunkEx.dwChannelMask = SPKRS_SURR_6_1;
  1667. break;
  1668. /* OCT 2009 */
  1669. case(MC_SURR_7_1):
  1670. if(props->chans /*!=*/ < 8){
  1671. rsferrno = ESFBADPARAM;
  1672. rsferrstr = "conflicting channel configuration for WAVE-EX file";
  1673. return 1;
  1674. }
  1675. f->fmtchunkEx.dwChannelMask = SPKRS_SURR_7_1;
  1676. break;
  1677. case(MC_CUBE):
  1678. if(props->chans /*!=*/ < 8){
  1679. rsferrno = ESFBADPARAM;
  1680. rsferrstr = "conflicting channel configuration for WAVE-EX file";
  1681. return 1;
  1682. }
  1683. f->fmtchunkEx.dwChannelMask = SPKRS_CUBE;
  1684. break;
  1685. default:
  1686. rsferrno = ESFBADPARAM;
  1687. rsferrstr = "unsupported channel configuration for WAVE-EX file";
  1688. return 1;
  1689. break;
  1690. }
  1691. if(write_dw_msf(TAG('f','m','t',' '), f)
  1692. ||write_dw_lsf(sizeof_WFMTEX, f) //RWD CDP97: size = 18 to include cbSize field
  1693. #if defined _WIN32
  1694. ||((f->fmtchunkoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF)
  1695. ||write_w_lsf(f->fmtchunkEx.Format.wFormatTag, f)
  1696. ||write_w_lsf(f->fmtchunkEx.Format.nChannels, f)
  1697. ||write_dw_lsf(f->fmtchunkEx.Format.nSamplesPerSec, f)
  1698. ||write_dw_lsf(f->fmtchunkEx.Format.nAvgBytesPerSec, f)
  1699. ||write_w_lsf(f->fmtchunkEx.Format.nBlockAlign, f)
  1700. ||write_w_lsf(f->fmtchunkEx.Format.wBitsPerSample, f)
  1701. ||write_w_lsf(cbSize,f)
  1702. )
  1703. goto ioerror;
  1704. #else
  1705. ||fgetpos(f->fileno, &bytepos)
  1706. ||write_w_lsf(f->fmtchunkEx.Format.wFormatTag, f)
  1707. ||write_w_lsf(f->fmtchunkEx.Format.nChannels, f)
  1708. ||write_dw_lsf(f->fmtchunkEx.Format.nSamplesPerSec, f)
  1709. ||write_dw_lsf(f->fmtchunkEx.Format.nAvgBytesPerSec, f)
  1710. ||write_w_lsf(f->fmtchunkEx.Format.nBlockAlign, f)
  1711. ||write_w_lsf(f->fmtchunkEx.Format.wBitsPerSample, f)
  1712. ||write_w_lsf(cbSize,f)
  1713. )
  1714. goto ioerror;
  1715. f->fmtchunkoffset = bytepos;
  1716. #endif
  1717. //don't need fact chunk unless actually a compressed format...
  1718. guid = *pGuid;
  1719. #ifdef MSBFIRST
  1720. guid.Data1 = REVDWBYTES(guid.Data1);
  1721. guid.Data2 = REVWBYTES(guid.Data2);
  1722. guid.Data3 = REVWBYTES(guid.Data3);
  1723. #endif
  1724. if(write_w_lsf(f->fmtchunkEx.Samples.wValidBitsPerSample,f)
  1725. || write_dw_lsf(f->fmtchunkEx.dwChannelMask,f)
  1726. || dowrite(f,(char *) &guid,sizeof(GUID)) /* RWD NB deal with byte-reversal sometime! */
  1727. )
  1728. goto ioerror;
  1729. // ADD the PEAK chunk
  1730. if((f->min_header>=SFILE_PEAKONLY) && f->peaks){
  1731. int i,size;
  1732. DWORD now = 0;
  1733. for(i=0;i < props->chans; i++){
  1734. f->peaks[i].value = 0.0f;
  1735. f->peaks[i].position = 0;
  1736. }
  1737. size = 2 * sizeof(DWORD) + props->chans * sizeof(CHPEAK);
  1738. if(write_dw_msf(TAG('P','E','A','K'),f)
  1739. || write_dw_lsf(size,f)
  1740. #if defined _WIN32
  1741. || ((f->peakchunkoffset = SetFilePointer(f->fileno,0L,NULL, FILE_CURRENT))== 0xFFFFFFFF)
  1742. || write_dw_lsf(CURRENT_PEAK_VERSION,f)
  1743. || write_dw_lsf(now,f)
  1744. || write_peak_lsf(props->chans,f))
  1745. goto ioerror;
  1746. #else
  1747. || fgetpos(f->fileno, &bytepos)
  1748. || write_dw_lsf(CURRENT_PEAK_VERSION,f)
  1749. || write_dw_lsf(now,f)
  1750. || write_peak_lsf(props->chans,f))
  1751. goto ioerror;
  1752. f->peakchunkoffset = bytepos;
  1753. #endif
  1754. }
  1755. if(f->min_header>=SFILE_CDP){
  1756. /*
  1757. * add the cue point/note chunk for properties
  1758. */
  1759. //RWD TODO: add switch to skip writing this extra stuff!
  1760. if(write_dw_msf(TAG('c','u','e',' '), f)
  1761. ||write_dw_lsf(sizeof(struct cuepoint) + sizeof(DWORD), f) )
  1762. goto ioerror;
  1763. cue.name = TAG('s','f','i','f');
  1764. cue.position = 0;
  1765. cue.incchunkid = TAG('d','a','t','a');
  1766. cue.chunkoffset = 0;
  1767. cue.blockstart = 0;
  1768. cue.sampleoffset = 0;
  1769. if(write_dw_lsf(1, f) /* one cue point */
  1770. ||write_dw_msf(cue.name, f)
  1771. ||write_dw_lsf(cue.position, f)
  1772. ||write_dw_msf(cue.incchunkid, f)
  1773. ||write_dw_lsf(cue.chunkoffset, f)
  1774. ||write_dw_lsf(cue.blockstart, f)
  1775. ||write_dw_lsf(cue.sampleoffset, f) )
  1776. goto ioerror;
  1777. /*... add a LIST chunk of type 'adtl'... */
  1778. if(write_dw_msf(TAG('L','I','S','T'), f)
  1779. ||write_dw_lsf(sizeof(DWORD) + 3*sizeof(DWORD) + PROPCNKSIZE, f)
  1780. ||write_dw_msf(TAG('a','d','t','l'), f) )
  1781. goto ioerror;
  1782. /* add the property-space note chunk */
  1783. if(write_dw_msf(TAG('n','o','t','e'), f)
  1784. ||write_dw_lsf(sizeof(DWORD) + PROPCNKSIZE, f)
  1785. ||write_dw_msf(TAG('s','f','i','f'), f)
  1786. #if defined _WIN32
  1787. ||((f->propoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF)
  1788. ||SetFilePointer(f->fileno, (long)PROPCNKSIZE,NULL, FILE_CURRENT) == 0xFFFFFFFF )
  1789. goto ioerror;
  1790. #else
  1791. ||fgetpos(f->fileno, &bytepos)
  1792. ||fseek(f->fileno, (long)PROPCNKSIZE, SEEK_CUR) < 0)
  1793. goto ioerror;
  1794. f->propoffset = bytepos;
  1795. #endif
  1796. f->propschanged = 1;
  1797. f->proplim = PROPCNKSIZE;
  1798. }
  1799. /*
  1800. * and add the data chunk
  1801. */
  1802. f->datachunksize = 0;
  1803. if(write_dw_msf(TAG('d','a','t','a'), f)
  1804. ||write_dw_lsf(0, f)
  1805. #if defined _WIN32
  1806. ||((f->datachunkoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF))
  1807. goto ioerror;
  1808. #else
  1809. ||fgetpos(f->fileno, &bytepos))
  1810. goto ioerror;
  1811. f->datachunkoffset = bytepos;
  1812. #endif
  1813. f->header_set = 1; //later, may allow update prior to first write ?
  1814. return 0;
  1815. /* NOTREACHED */
  1816. ioerror:
  1817. rsferrno = ESFWRERR;
  1818. rsferrstr = "error writing wav_ex header";
  1819. return 1;
  1820. }
  1821. /*
  1822. * aiff routines
  1823. */
  1824. //RWD98 BUG, SOMEWHERE: THIS READS THE SSND CHUNK, AND GETS SIZE = REMAIN; BUT REMAIN SHOULD BE SIZE + 8
  1825. // SO, EITHER BUG IN THIS CODE, OR IN WRAIFFHDR... SO CANNOT USE WINDOWS DWORD 'COS UNSIGNED....
  1826. //RWD.6.99 NOTE: some tests require the Fomat field to be set, even though this is aiff
  1827. //RWD.7.99: accept masked AIFF formats: container size is always next intergral number of bytes
  1828. static int
  1829. rdaiffhdr(struct sf_file *f)
  1830. {
  1831. DWORD /*long */ tag, size = 0, remain = 0, appltag; //RWD.04.98 can't be unsigned until the size anomalies are resolved
  1832. DWORD peaktime; /* RWD Jan 2005 */
  1833. int commseen = 0, ssndseen = 0;
  1834. DWORD numsampleframes;
  1835. DWORD ssnd_offset, ssnd_blocksize;
  1836. fpos_t bytepos;
  1837. POS64(bytepos) = 0;
  1838. char *propspace;
  1839. DWORD peak_version;
  1840. // WARNING! The file can have the wrong size (e.g. from sox)
  1841. if(read_dw_msf(&tag, f)
  1842. ||read_dw_msf(&remain, f)
  1843. ||tag != TAG('F','O','R','M')) {
  1844. rsferrno = ESFNOTFOUND;
  1845. rsferrstr = "File is not an AIFF file";
  1846. return 1;
  1847. }
  1848. if(remain < 3*sizeof(DWORD)) {
  1849. rsferrno = ESFNOTFOUND;
  1850. rsferrstr = "File data size is too small";
  1851. return 1;
  1852. }
  1853. if(read_dw_msf(&tag, f)
  1854. ||tag != TAG('A','I','F','F')) {
  1855. rsferrno = ESFNOTFOUND;
  1856. rsferrstr = "File does not include an AIFF form";
  1857. return 1;
  1858. }
  1859. f->mainchunksize = remain;
  1860. f->extrachunksizes = 0;
  1861. POS64(f->propoffset) = -1;
  1862. f->aiffchunks = 0;
  1863. remain -= sizeof(DWORD);
  1864. while(remain > 0) {
  1865. if(read_dw_msf(&tag, f)
  1866. ||read_dw_msf(&size,f)){
  1867. if(ssndseen && commseen){ //RWD accept the file anyway if we have enough
  1868. remain = 0;
  1869. break;
  1870. }
  1871. else
  1872. goto ioerror;
  1873. }
  1874. remain -= 2*sizeof(DWORD);
  1875. switch(tag) {
  1876. case TAG('C','O','M','M'):
  1877. if(size != 18) {
  1878. rsferrno = ESFNOTFOUND;
  1879. rsferrstr = "AIFF COMM chunk of incorrect size";
  1880. return 1;
  1881. }
  1882. #if defined _WIN32
  1883. if((f->fmtchunkoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF
  1884. ||read_w_msf(&f->fmtchunkEx.Format.nChannels, f)
  1885. ||read_dw_msf(&numsampleframes, f)
  1886. ||read_w_msf(&f->fmtchunkEx.Format.wBitsPerSample, f)
  1887. ||read_ex_todw(&f->fmtchunkEx.Format.nSamplesPerSec, f) )
  1888. goto ioerror;
  1889. #else
  1890. if(fgetpos(f->fileno, &bytepos)
  1891. ||read_w_msf(&f->fmtchunkEx.Format.nChannels, f)
  1892. ||read_dw_msf(&numsampleframes, f)
  1893. ||read_w_msf(&f->fmtchunkEx.Format.wBitsPerSample, f)
  1894. ||read_ex_todw(&f->fmtchunkEx.Format.nSamplesPerSec, f) )
  1895. goto ioerror;
  1896. f->fmtchunkoffset = bytepos;
  1897. #endif
  1898. /*RWD Trevor uses srate of zero for envel files! */
  1899. /* nSamples... is unsigned anyway, so dont bother with this one any more... */
  1900. #ifdef NOTDEF
  1901. if(f->fmtchunkEx.Format.nSamplesPerSec < 0) {
  1902. rsferrno = ESFNOTFOUND;
  1903. rsferrstr = "Unknown AIFF sample rate";
  1904. return 1;
  1905. }
  1906. #endif
  1907. /*RWD.7.99 we now read 32bit in standard AIFF as LONGS
  1908. * we rely on the extra properties to tell if it's an analysis file */
  1909. f->fmtchunkEx.Format.wFormatTag = WAVE_FORMAT_PCM;
  1910. //fill in other info
  1911. f->fmtchunkEx.Samples.wValidBitsPerSample = f->fmtchunkEx.Format.wBitsPerSample;
  1912. //we have to deduce blockalign, and hence containersize
  1913. switch(f->fmtchunkEx.Samples.wValidBitsPerSample){
  1914. case(32):
  1915. f->fmtchunkEx.Format.nBlockAlign = sizeof(/*long*/int);
  1916. break;
  1917. case(20):
  1918. case(24):
  1919. f->fmtchunkEx.Format.nBlockAlign = 3;
  1920. break;
  1921. case(16):
  1922. f->fmtchunkEx.Format.nBlockAlign = sizeof(short);
  1923. break;
  1924. case(8):
  1925. f->fmtchunkEx.Format.nBlockAlign = sizeof(char);
  1926. break;
  1927. default:
  1928. rsferrno = ESFNOTFOUND;
  1929. rsferrstr = "unsupported sample size in aiff file";
  1930. return 1;
  1931. }
  1932. f->fmtchunkEx.Format.nBlockAlign *= f->fmtchunkEx.Format.nChannels;
  1933. //should do avgBytesPerSec too...
  1934. f->fmtchunkEx.dwChannelMask = 0;
  1935. remain -= 18;
  1936. commseen++;
  1937. break;
  1938. //RWD.5.99 read PEAK chunk
  1939. case TAG('P','E','A','K'):
  1940. f->peaks = (CHPEAK *) calloc(f->fmtchunkEx.Format.nChannels,sizeof(CHPEAK));
  1941. if(f->peaks == NULL){
  1942. rsferrno = ESFNOMEM;
  1943. rsferrstr = "No memory for peak data";
  1944. return 1;
  1945. }
  1946. if(read_dw_msf(&peak_version,f))
  1947. goto ioerror;
  1948. switch(peak_version){
  1949. case(CURRENT_PEAK_VERSION):
  1950. if(read_dw_msf(&peaktime,f)) /* RWD Jan 2005 for DevCPP */
  1951. goto ioerror;
  1952. f->peaktime = (time_t) peaktime;
  1953. #if defined _WIN32
  1954. if((f->peakchunkoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF
  1955. || read_peak_msf(f->fmtchunkEx.Format.nChannels,f))
  1956. goto ioerror;
  1957. #else
  1958. if(fgetpos(f->fileno, &bytepos)
  1959. || read_peak_msf(f->fmtchunkEx.Format.nChannels,f))
  1960. goto ioerror;
  1961. f->peakchunkoffset = bytepos;
  1962. #endif
  1963. break;
  1964. default:
  1965. #ifdef _DEBUG
  1966. fprintf(stderr,"\nunknown PEAK version!");
  1967. #endif
  1968. free(f->peaks);
  1969. f->peaks = NULL;
  1970. break;
  1971. }
  1972. remain -= 2 * sizeof(DWORD) + (sizeof(CHPEAK) * f->fmtchunkEx.Format.nChannels);
  1973. break;
  1974. case TAG('S','S','N','D'):
  1975. if(read_dw_msf(&ssnd_offset, f)
  1976. ||read_dw_msf(&ssnd_blocksize, f)
  1977. #if defined _WIN32
  1978. ||(f->datachunkoffset = SetFilePointer(f->fileno, 0L,NULL,FILE_CURRENT)) ==0xFFFFFFFF
  1979. || SetFilePointer(f->fileno, ((size+1)&~1) - 2 *sizeof(DWORD),NULL,FILE_CURRENT) ==0xFFFFFFFF)
  1980. goto ioerror;
  1981. #else
  1982. || fgetpos(f->fileno, &bytepos))
  1983. goto ioerror;
  1984. f->datachunkoffset = bytepos;
  1985. POS64(bytepos) += ((size+1)&~1) - 2 *sizeof(DWORD);
  1986. /*fseek(f->fileno, ((size+1)&~1) - 2 *sizeof(DWORD), SEEK_CUR) < 0) */
  1987. if(fsetpos(f->fileno,&bytepos))
  1988. goto ioerror;
  1989. #endif
  1990. remain -= 2 * sizeof(DWORD); /* RWD Apr 2011 need this */
  1991. /* RWD MAR 2015 eliminate warning, ssnd_offset is unsigned */
  1992. if(/* ssnd_offset < 0 || */ ssnd_offset > ssnd_blocksize) {
  1993. rsferrno = ESFNOTFOUND;
  1994. rsferrstr = "Funny offset in AIFF SSND chunk";
  1995. return 1;
  1996. }
  1997. POS64(f->datachunkoffset) += ssnd_offset;
  1998. ssndseen++;
  1999. remain -= (size+1)&~1; //RWD98 BUG!!! remain can get less than size...
  2000. break;
  2001. case 0:
  2002. rsferrno = ESFNOTFOUND;
  2003. rsferrstr = "Illegal zero tag in aiff chunk";
  2004. return 1;
  2005. case TAG('A','P','P','L'):
  2006. if(size < sizeof(DWORD)
  2007. ||read_dw_msf(&appltag,f) )
  2008. goto ioerror;
  2009. if(appltag == TAG('s','f','i','f')) {
  2010. if(POS64(f->propoffset) >= 0
  2011. ||(propspace = (char *) malloc(size - sizeof(DWORD))) == 0
  2012. #if defined _WIN32
  2013. ||(f->propoffset = SetFilePointer(f->fileno, 0L,NULL,FILE_CURRENT))==0xFFFFFFFF
  2014. ||doread(f, propspace, size-sizeof(DWORD)) )
  2015. goto ioerror;
  2016. #else
  2017. ||fgetpos(f->fileno, &bytepos)
  2018. ||doread(f, propspace, size-sizeof(DWORD)) )
  2019. goto ioerror;
  2020. POS64(f->propoffset) = POS64(bytepos);
  2021. #endif
  2022. f->proplim = size - sizeof(DWORD);
  2023. parseprops(f, propspace);
  2024. if(size&1)
  2025. doread(f, propspace, 1);
  2026. free(propspace);
  2027. break;
  2028. } else {
  2029. #if defined _WIN32
  2030. if(SetFilePointer(f->fileno,-4L,NULL,FILE_CURRENT) == 0xFFFFFFFF)
  2031. #else
  2032. if(fseek(f->fileno, -4L, SEEK_CUR) < 0)
  2033. #endif
  2034. goto ioerror;
  2035. }
  2036. /* FALLTHROUGH */
  2037. default:
  2038. /* RWD MAR 2015: size is unsigned, eliminate warning! */
  2039. #ifdef NOTDEF
  2040. if(size < 0 /* || size > 100*1024 */) { /* RWD Apr 2011 */
  2041. rsferrno = ESFNOTFOUND;
  2042. rsferrstr = "Silly size for unknown AIFF chunk";
  2043. return 1;
  2044. }
  2045. #endif
  2046. if(ssndseen) {
  2047. struct aiffchunk **cpp, *cp;
  2048. for(cpp = &f->aiffchunks; *cpp != 0; cpp = &(*cpp)->next)
  2049. ;
  2050. if((*cpp = cp = ALLOC(struct aiffchunk)) == 0
  2051. ||(cp->buf = (char *) malloc((size+1)&~1)) == 0) {
  2052. rsferrno = ESFNOMEM;
  2053. rsferrstr = "No memory for aiff chunk storage";
  2054. return 1;
  2055. }
  2056. cp->tag = tag;
  2057. cp->size = size;
  2058. cp->next = 0;
  2059. #if defined _WIN32
  2060. if((cp->offset = SetFilePointer(f->fileno,0L,NULL,FILE_CURRENT)) == 0xFFFFFFFF
  2061. ||doread(f, cp->buf, (size+1)&~1))
  2062. goto ioerror;
  2063. #else
  2064. if(fgetpos(f->fileno,&bytepos)
  2065. ||doread(f, cp->buf, (size+1)&~1))
  2066. goto ioerror;
  2067. cp->offset = bytepos;
  2068. #endif
  2069. } else {
  2070. #if defined _WIN32
  2071. if(SetFilePointer(f->fileno,(long)((size+1)&~1),NULL,FILE_CURRENT) == 0xFFFFFFFF)
  2072. #else
  2073. if(fseeko(f->fileno, (size+1)&~1, SEEK_CUR) < 0)
  2074. #endif
  2075. goto ioerror;
  2076. }
  2077. f->extrachunksizes += ((size+1)&~1) + 2*sizeof(DWORD);
  2078. remain -= (size+1)&~1;
  2079. break;
  2080. }
  2081. }
  2082. if(!commseen) {
  2083. rsferrno = ESFNOTFOUND;
  2084. rsferrstr = "AIFF format error: no COMM chunk found";
  2085. return 1;
  2086. }
  2087. if(!ssndseen) {
  2088. rsferrno = ESFNOTFOUND;
  2089. rsferrstr = "AIFF format error: no SSND chunk found";
  2090. return 1;
  2091. }
  2092. f->datachunksize = numsampleframes * f->fmtchunkEx.Format.nChannels;
  2093. switch(f->fmtchunkEx.Format.wBitsPerSample) {
  2094. case 32: /* floats */
  2095. f->datachunksize *= 4;
  2096. break;
  2097. case 20:
  2098. case 24:
  2099. f->datachunksize *= 3;
  2100. break;
  2101. case 16: /* shorts */
  2102. f->datachunksize *= 2;
  2103. break;
  2104. case 8: /* byte -> short mappping */
  2105. f->datachunksize *= 2; /* looks like short samples! */
  2106. break;
  2107. default:
  2108. rsferrno = ESFNOTFOUND;
  2109. rsferrstr = "can't open aiff file - unsupported wordsize";
  2110. return 1;
  2111. }
  2112. #if defined _WIN32
  2113. if(SetFilePointer(f->fileno,f->datachunkoffset,NULL,FILE_BEGIN)==0xFFFFFFFF)
  2114. #else
  2115. bytepos = f->datachunkoffset;
  2116. if(fsetpos(f->fileno, &bytepos) < 0)
  2117. #endif
  2118. goto ioerror;
  2119. return 0;
  2120. /* NOTREACHED */
  2121. ioerror:
  2122. rsferrno = ESFRDERR;
  2123. rsferrstr = "read error (or file too short) reading AIFF header";
  2124. return 1;
  2125. }
  2126. /*AIF-C*/
  2127. #define AIFC_VERSION_1 (0xA2805140)
  2128. static int
  2129. rdaifchdr(struct sf_file *f)
  2130. {
  2131. DWORD tag, size = 0, remain = 0, appltag;
  2132. int commseen = 0, ssndseen = 0,fmtverseen = 0;
  2133. DWORD numsampleframes, aifcver,ID_compression;
  2134. DWORD ssnd_offset, ssnd_blocksize;
  2135. char *propspace;
  2136. DWORD peak_version;
  2137. DWORD peaktime;
  2138. fpos_t bytepos;
  2139. if(read_dw_msf(&tag, f)
  2140. ||read_dw_msf(&remain, f)
  2141. ||tag != TAG('F','O','R','M')) {
  2142. rsferrno = ESFNOTFOUND;
  2143. rsferrstr = "File is not an AIFF file";
  2144. return 1;
  2145. }
  2146. if(remain < 3*sizeof(DWORD)) {
  2147. rsferrno = ESFNOTFOUND;
  2148. rsferrstr = "File data size is too small";
  2149. return 1;
  2150. }
  2151. if(read_dw_msf(&tag, f)
  2152. ||tag != TAG('A','I','F','C')) {
  2153. rsferrno = ESFNOTFOUND;
  2154. rsferrstr = "File does not include an AIFC form";
  2155. return 1;
  2156. }
  2157. f->mainchunksize = remain;
  2158. f->extrachunksizes = 0;
  2159. POS64(f->propoffset) = -1;
  2160. f->aiffchunks = 0;
  2161. //start by assuming integer format:
  2162. f->fmtchunkEx.Format.wFormatTag = WAVE_FORMAT_PCM;
  2163. remain -= sizeof(DWORD);
  2164. while(remain > 0) {
  2165. if(read_dw_msf(&tag, f)
  2166. ||read_dw_msf(&size,f)){
  2167. if(ssndseen && commseen){ //RWD accept the file anyway if we have enough
  2168. remain = 0;
  2169. break;
  2170. }
  2171. else
  2172. goto ioerror;
  2173. }
  2174. remain -= 2*sizeof(DWORD);
  2175. switch(tag) {
  2176. case TAG('F','V','E','R'):
  2177. if(size != 4){
  2178. rsferrno = ESFNOTFOUND;
  2179. rsferrstr = "bad aif-c FVER chunk";
  2180. return 1;
  2181. }
  2182. if(read_dw_msf(&aifcver,f) || aifcver != AIFC_VERSION_1){
  2183. rsferrno = ESFNOTFOUND;
  2184. rsferrstr = "bad aif-c Version";
  2185. return 1;
  2186. }
  2187. remain -= sizeof(DWORD);
  2188. fmtverseen++;
  2189. break;
  2190. case TAG('C','O','M','M'):
  2191. if(size < 22) {
  2192. rsferrno = ESFNOTFOUND;
  2193. rsferrstr = "AIFC COMM chunk of incorrect size";
  2194. return 1;
  2195. }
  2196. #if defined _WIN32
  2197. if((f->fmtchunkoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF
  2198. ||read_w_msf(&f->fmtchunkEx.Format.nChannels, f)
  2199. ||read_dw_msf(&numsampleframes, f)
  2200. ||read_w_msf(&f->fmtchunkEx.Format.wBitsPerSample, f)
  2201. ||read_ex_todw(&f->fmtchunkEx.Format.nSamplesPerSec, f) )
  2202. goto ioerror;
  2203. #else
  2204. if(fgetpos(f->fileno, &bytepos)
  2205. ||read_w_msf(&f->fmtchunkEx.Format.nChannels, f)
  2206. ||read_dw_msf(&numsampleframes, f)
  2207. ||read_w_msf(&f->fmtchunkEx.Format.wBitsPerSample, f)
  2208. ||read_ex_todw(&f->fmtchunkEx.Format.nSamplesPerSec, f) )
  2209. goto ioerror;
  2210. f->fmtchunkoffset = bytepos;
  2211. #endif
  2212. /*RWD: Trevor uses srate of zero for envel files! */
  2213. /* RWD MAR 2015: so eliminate code to avoid warning, as above */
  2214. #ifdef NOTDEF
  2215. if(f->fmtchunkEx.Format.nSamplesPerSec < 0) {
  2216. rsferrno = ESFNOTFOUND;
  2217. rsferrstr = "Unknown AIFC sample rate";
  2218. return 1;
  2219. }
  2220. #endif
  2221. if(read_dw_msf(&ID_compression,f))
  2222. goto ioerror;
  2223. if( !(
  2224. (ID_compression == TAG('N','O','N','E'))
  2225. || (ID_compression == TAG('F','L','3','2')) //Csound
  2226. || (ID_compression == TAG('f','l','3','2')) //Apple
  2227. /* used in Steinberg 24bit SDIR files */
  2228. || (ID_compression == TAG('i','n','2','4'))
  2229. )){
  2230. rsferrno = ESFNOTFOUND;
  2231. rsferrstr = "Unknown AIFC compression type";
  2232. return 1;
  2233. }
  2234. //set sample type in sfinfo
  2235. if((ID_compression== TAG('F','L','3','2'))
  2236. || ID_compression == TAG('f','l','3','2')){
  2237. /*Nov 2001: F***** Quicktime writes size = 16, for floats! */
  2238. if(f->fmtchunkEx.Format.wBitsPerSample != 32){
  2239. if(f->fmtchunkEx.Format.wBitsPerSample != 16){
  2240. rsferrno = ESFNOTFOUND;
  2241. rsferrstr = "error in AIFC header: samples not 32bit in floats file ";
  2242. return 1;
  2243. }
  2244. else
  2245. f->fmtchunkEx.Format.wBitsPerSample = 32;
  2246. }
  2247. f->fmtchunkEx.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
  2248. }
  2249. /* RWD 06/01/09 precautionary, to validate 'in24' 24bit files */
  2250. if(ID_compression == TAG('i','n','2','4')) {
  2251. if(f->fmtchunkEx.Format.wBitsPerSample != 24){
  2252. rsferrstr = "error in AIFC header: sample size not 24bit in <in24> file ";
  2253. return 1;
  2254. }
  2255. }
  2256. //no ambiguity here with 32bit format.
  2257. //fill in other info
  2258. f->fmtchunkEx.Samples.wValidBitsPerSample = f->fmtchunkEx.Format.wBitsPerSample;
  2259. f->fmtchunkEx.dwChannelMask = 0;
  2260. //we have to deduce blockalign, and hence containersize
  2261. switch(f->fmtchunkEx.Samples.wValidBitsPerSample){
  2262. case(32):
  2263. f->fmtchunkEx.Format.nBlockAlign = sizeof(/*long*/int);
  2264. break;
  2265. case(20):
  2266. case(24):
  2267. f->fmtchunkEx.Format.nBlockAlign = 3;
  2268. break;
  2269. case(16):
  2270. f->fmtchunkEx.Format.nBlockAlign = sizeof(short);
  2271. break;
  2272. case(8):
  2273. f->fmtchunkEx.Format.nBlockAlign = sizeof(char);
  2274. break;
  2275. default:
  2276. rsferrno = ESFNOTFOUND;
  2277. rsferrstr = "unsupported sample size in aiff file";
  2278. return 1;
  2279. }
  2280. f->fmtchunkEx.Format.nBlockAlign *= f->fmtchunkEx.Format.nChannels;
  2281. //should do avgBytesPerSec too...
  2282. /*RWD 23:10:2000 can get odd sizes... */
  2283. //skip past pascal string
  2284. #if defined _WIN32
  2285. if(SetFilePointer(f->fileno, ((size+1)&~1) - 22,NULL,FILE_CURRENT) ==0xFFFFFFFF)
  2286. #else
  2287. if(fseek(f->fileno,((size+1)&~1) - 22,SEEK_CUR) < 0)
  2288. #endif
  2289. goto ioerror;
  2290. remain -= (size+1)&~1;
  2291. commseen++;
  2292. break;
  2293. //RWD.5.99 read PEAK chunk
  2294. case TAG('P','E','A','K'):
  2295. f->peaks = (CHPEAK *) calloc(f->fmtchunkEx.Format.nChannels,sizeof(CHPEAK));
  2296. if(f->peaks == NULL){
  2297. rsferrno = ESFNOMEM;
  2298. rsferrstr = "No memory for peak data";
  2299. return 1;
  2300. }
  2301. if(read_dw_msf(&peak_version,f))
  2302. goto ioerror;
  2303. switch(peak_version){
  2304. case(CURRENT_PEAK_VERSION):
  2305. if(read_dw_msf(&peaktime,f))
  2306. goto ioerror;
  2307. f->peaktime = (time_t) peaktime;
  2308. #if defined _WIN32
  2309. if((f->peakchunkoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF
  2310. || read_peak_msf(f->fmtchunkEx.Format.nChannels,f))
  2311. goto ioerror;
  2312. #else
  2313. if(fgetpos(f->fileno, &bytepos)
  2314. || read_peak_msf(f->fmtchunkEx.Format.nChannels,f))
  2315. goto ioerror;
  2316. f->peakchunkoffset = bytepos;
  2317. #endif
  2318. break;
  2319. default:
  2320. #ifdef _DEBUG
  2321. fprintf(stderr,"\nunknown PEAK version!");
  2322. #endif
  2323. free(f->peaks);
  2324. f->peaks = NULL;
  2325. break;
  2326. }
  2327. remain -= 2 * sizeof(DWORD) + (sizeof(CHPEAK) * f->fmtchunkEx.Format.nChannels);
  2328. break;
  2329. case TAG('S','S','N','D'):
  2330. if(read_dw_msf(&ssnd_offset, f)
  2331. ||read_dw_msf(&ssnd_blocksize, f)
  2332. #if defined _WIN32
  2333. ||(f->datachunkoffset = SetFilePointer(f->fileno, 0L,NULL,FILE_CURRENT)) ==0xFFFFFFFF
  2334. || SetFilePointer(f->fileno, ((size+1)&~1) - 2 *sizeof(DWORD),NULL,FILE_CURRENT) ==0xFFFFFFFF)
  2335. goto ioerror;
  2336. if(ssnd_offset < 0 || ssnd_offset > ssnd_blocksize) {
  2337. rsferrno = ESFNOTFOUND;
  2338. rsferrstr = "Funny offset in AIFC SSND chunk";
  2339. return 1;
  2340. }
  2341. f->datachunkoffset += ssnd_offset;
  2342. #else
  2343. ||fgetpos(f->fileno, &bytepos) )
  2344. goto ioerror;
  2345. f->datachunkoffset = bytepos;
  2346. POS64(bytepos) = ((size+1)&~1) - 2 *sizeof(DWORD);
  2347. if(fseeko(f->fileno,POS64(bytepos), SEEK_CUR) < 0)
  2348. goto ioerror;
  2349. /* RWD MAR 2015 ssnd_offset unsigned, eliminate compiler warning */
  2350. if(/* ssnd_offset < 0 || */ ssnd_offset > ssnd_blocksize) {
  2351. rsferrno = ESFNOTFOUND;
  2352. rsferrstr = "Funny offset in AIFC SSND chunk";
  2353. return 1;
  2354. }
  2355. POS64(f->datachunkoffset) += ssnd_offset;
  2356. #endif
  2357. ssndseen++;
  2358. remain -= (size+1)&~1; //RWD98 BUG!!! remain can get less than size...
  2359. break;
  2360. case 0:
  2361. rsferrno = ESFNOTFOUND;
  2362. rsferrstr = "Illegal zero tag in aifc chunk";
  2363. return 1;
  2364. case TAG('A','P','P','L'):
  2365. if(size < sizeof(DWORD)
  2366. ||read_dw_msf(&appltag,f) )
  2367. goto ioerror;
  2368. if(appltag == TAG('s','f','i','f')) {
  2369. if(POS64(f->propoffset) >= 0
  2370. ||(propspace = (char *) malloc(size - sizeof(DWORD))) == 0
  2371. #if defined _WIN32
  2372. ||(f->propoffset = SetFilePointer(f->fileno, 0L,NULL,FILE_CURRENT))==0xFFFFFFFF
  2373. ||doread(f, propspace, size-sizeof(DWORD)) )
  2374. goto ioerror;
  2375. #else
  2376. ||fgetpos(f->fileno, &bytepos)
  2377. ||doread(f, propspace, size-sizeof(DWORD)) )
  2378. goto ioerror;
  2379. f->propoffset = bytepos;
  2380. #endif
  2381. f->proplim = size - sizeof(DWORD);
  2382. parseprops(f, propspace);
  2383. if(size&1)
  2384. doread(f, propspace, 1);
  2385. free(propspace);
  2386. break;
  2387. } else {
  2388. #if defined _WIN32
  2389. if(SetFilePointer(f->fileno,-4L,NULL,FILE_CURRENT) == 0xFFFFFFFF)
  2390. #else
  2391. if(fseek(f->fileno, -4L, SEEK_CUR) < 0)
  2392. #endif
  2393. goto ioerror;
  2394. }
  2395. /* FALLTHROUGH */
  2396. default:
  2397. /* RWD MAR 2015 eliminate compiler warning; bit of an arbitrary exclusion anyway? */
  2398. if(/* size < 0 || */ size > 100*1024) {
  2399. rsferrno = ESFNOTFOUND;
  2400. rsferrstr = "Silly size for unknown AIFC chunk";
  2401. return 1;
  2402. }
  2403. if(ssndseen) {
  2404. struct aiffchunk **cpp, *cp;
  2405. for(cpp = &f->aiffchunks; *cpp != 0; cpp = &(*cpp)->next)
  2406. ;
  2407. if((*cpp = cp = ALLOC(struct aiffchunk)) == 0
  2408. ||(cp->buf = (char *) malloc((size+1)&~1)) == 0) {
  2409. rsferrno = ESFNOMEM;
  2410. rsferrstr = "No memory for aifc chunk storage";
  2411. return 1;
  2412. }
  2413. cp->tag = tag;
  2414. cp->size = size;
  2415. cp->next = 0;
  2416. #if defined _WIN32
  2417. if((cp->offset = SetFilePointer(f->fileno,0L,NULL,FILE_CURRENT)) == 0xFFFFFFFF
  2418. ||doread(f, cp->buf, (size+1)&~1))
  2419. goto ioerror;
  2420. #else
  2421. if(fgetpos(f->fileno, &bytepos)
  2422. ||doread(f, cp->buf, (size+1)&~1))
  2423. goto ioerror;
  2424. cp->offset = bytepos;
  2425. #endif
  2426. } else {
  2427. #if defined _WIN32
  2428. if(SetFilePointer(f->fileno,(long)((size+1)&~1),NULL,FILE_CURRENT) == 0xFFFFFFFF)
  2429. goto ioerror;
  2430. #else
  2431. if(fgetpos(f->fileno, &bytepos))
  2432. goto ioerror;
  2433. POS64(bytepos) += (size+1)&~1;
  2434. if(fsetpos(f->fileno, &bytepos))
  2435. goto ioerror;
  2436. #endif
  2437. }
  2438. f->extrachunksizes += ((size+1)&~1) + 2*sizeof(DWORD);
  2439. remain -= (size+1)&~1;
  2440. break;
  2441. }
  2442. }
  2443. if(!commseen) {
  2444. rsferrno = ESFNOTFOUND;
  2445. rsferrstr = "AIFC format error: no COMM chunk found";
  2446. return 1;
  2447. }
  2448. if(!ssndseen) {
  2449. rsferrno = ESFNOTFOUND;
  2450. rsferrstr = "AIFC format error: no SSND chunk found";
  2451. return 1;
  2452. }
  2453. if(!fmtverseen) {
  2454. rsferrno = ESFNOTFOUND;
  2455. rsferrstr = "AIFC format error: no FVER chunk found";
  2456. return 1;
  2457. }
  2458. f->datachunksize = numsampleframes * f->fmtchunkEx.Format.nChannels;
  2459. switch(f->fmtchunkEx.Format.wBitsPerSample) {
  2460. case 32: /* floats */
  2461. f->datachunksize *= 4;
  2462. break;
  2463. case 16: /* shorts */
  2464. f->datachunksize *= 2;
  2465. break;
  2466. case 20:
  2467. case 24:
  2468. f->datachunksize *= 3;
  2469. break;
  2470. case 8: /* byte -> short mappping */
  2471. f->datachunksize *= 2; /* looks like short samples! */
  2472. break;
  2473. default:
  2474. rsferrno = ESFNOTFOUND;
  2475. rsferrstr = "can't open Sfile - unsupported wordsize";
  2476. return 1;
  2477. }
  2478. #if defined _WIN32
  2479. if(SetFilePointer(f->fileno,f->datachunkoffset,NULL,FILE_BEGIN)==0xFFFFFFFF)
  2480. #else
  2481. POS64(bytepos) = POS64(f->datachunkoffset);
  2482. if(fsetpos(f->fileno, &bytepos) < 0)
  2483. #endif
  2484. goto ioerror;
  2485. return 0;
  2486. /* NOTREACHED */
  2487. ioerror:
  2488. rsferrno = ESFRDERR;
  2489. rsferrstr = "read error (or file too short) reading AIFC header";
  2490. return 1;
  2491. }
  2492. #if 0
  2493. static int
  2494. wraiffhdr(struct sf_file *f)
  2495. {
  2496. fpos_t bytepos;
  2497. f->mainchunksize = 0;
  2498. if(write_dw_msf(TAG('F','O','R','M'), f)
  2499. ||write_dw_msf(0, f)
  2500. ||write_dw_msf(TAG('A','I','F','F'), f) )
  2501. goto ioerror;
  2502. f->fmtchunkEx.Format.nChannels = 1;
  2503. f->fmtchunkEx.Format.nSamplesPerSec = 44100;
  2504. f->fmtchunkEx.Format.wBitsPerSample = 16;
  2505. f->aiffchunks = 0;
  2506. if(write_dw_msf(TAG('C','O','M','M'), f)
  2507. || write_dw_msf(18, f)
  2508. #if defined _WIN32
  2509. || (f->fmtchunkoffset = SetFilePointer(f->fileno,0L,NULL,FILE_CURRENT))==0xFFFFFFFF
  2510. || write_w_msf(f->fmtchunkEx.Format.nChannels, f)
  2511. || write_dw_msf(0, f) /* num sample frames */
  2512. || write_w_msf(f->fmtchunkEx.Format.wBitsPerSample, f)
  2513. || write_dw_toex(f->fmtchunkEx.Format.nSamplesPerSec, f) )
  2514. goto ioerror;
  2515. #else
  2516. ||fgetpos(f->fileno, &bytepos)
  2517. || write_w_msf(f->fmtchunkEx.Format.nChannels, f)
  2518. || write_dw_msf(0, f) /* num sample frames */
  2519. || write_w_msf(f->fmtchunkEx.Format.wBitsPerSample, f)
  2520. || write_dw_toex(f->fmtchunkEx.Format.nSamplesPerSec, f) )
  2521. goto ioerror;
  2522. f->fmtchunkoffset = bytepos;
  2523. #endif
  2524. if(write_dw_msf(TAG('A','P','P','L'), f)
  2525. || write_dw_msf(sizeof(DWORD) + PROPCNKSIZE, f)
  2526. || write_dw_msf(TAG('s','f','i','f'), f)
  2527. #if defined _WIN32
  2528. || (f->propoffset = SetFilePointer(f->fileno, 0L,NULL,FILE_CURRENT))==0xFFFFFFFF
  2529. || SetFilePointer(f->fileno,(long)PROPCNKSIZE,NULL,FILE_CURRENT) == 0xFFFFFFFF)
  2530. goto ioerror;
  2531. #else
  2532. || fgetpos(f->fileno, &bytepos)
  2533. || fseek(f->fileno, (long)PROPCNKSIZE, SEEK_CUR) < 0)
  2534. goto ioerror;
  2535. f->propoffset = bytepos;
  2536. #endif
  2537. if(write_dw_msf(TAG('S','S','N','D'), f)
  2538. || write_dw_msf(0, f)
  2539. || write_dw_msf(0, f) /* offset */
  2540. || write_dw_msf(0, f) /* blocksize */
  2541. #if defined _WIN32
  2542. || (f->datachunkoffset = SetFilePointer(f->fileno,0L,NULL,FILE_CURRENT)) == 0xFFFFFFFF)
  2543. goto ioerror;
  2544. #else
  2545. || fgetpos(f->fileno, &bytepos) )
  2546. goto ioerror;
  2547. f->datachunkoffset = bytepos;
  2548. #endif
  2549. f->propschanged = 1;
  2550. f->proplim = PROPCNKSIZE;
  2551. f->datachunksize = 0;
  2552. f->extrachunksizes = 0;
  2553. return 0;
  2554. /* NOTREACHED */
  2555. ioerror:
  2556. rsferrno = ESFWRERR;
  2557. rsferrstr = "write error writing aiff header";
  2558. return 1;
  2559. }
  2560. #endif
  2561. /*********** sfsys98 extension **********/
  2562. static int
  2563. wraiffhdr98(struct sf_file *f,int channels,int srate,int stype)
  2564. {
  2565. fpos_t bytepos;
  2566. if(stype >= SAMP_MASKED)
  2567. return 1;
  2568. rsferrstr = NULL;
  2569. f->mainchunksize = 0;
  2570. if(write_dw_msf(TAG('F','O','R','M'), f)
  2571. || write_dw_msf(0, f)
  2572. || write_dw_msf(TAG('A','I','F','F'), f) )
  2573. goto ioerror;
  2574. f->fmtchunkEx.Format.nChannels = (short)channels;
  2575. f->fmtchunkEx.Format.nSamplesPerSec = srate;
  2576. switch(stype){
  2577. case(SAMP_SHORT):
  2578. f->fmtchunkEx.Format.wBitsPerSample = 16;
  2579. f->fmtchunkEx.Format.nBlockAlign = sizeof(short) * f->fmtchunkEx.Format.nChannels;
  2580. break;
  2581. case(SAMP_FLOAT): //need to keep this for now...
  2582. case(SAMP_LONG):
  2583. f->fmtchunkEx.Format.wBitsPerSample = 32;
  2584. f->fmtchunkEx.Format.nBlockAlign = sizeof(/*long*/int) * f->fmtchunkEx.Format.nChannels;
  2585. break;
  2586. case(SAMP_2024):
  2587. f->fmtchunkEx.Format.wBitsPerSample = 20;
  2588. f->fmtchunkEx.Format.nBlockAlign = 3 * f->fmtchunkEx.Format.nChannels;
  2589. break;
  2590. case(SAMP_2424):
  2591. f->fmtchunkEx.Format.wBitsPerSample = 24;
  2592. f->fmtchunkEx.Format.nBlockAlign = 3 * f->fmtchunkEx.Format.nChannels;
  2593. break;
  2594. //NB 24/32 not allowed in AIFF
  2595. //case SAMP_MASKED: supported by AIFF, inside nearest integral byte-size
  2596. default:
  2597. rsferrstr = "sample format not supported in AIFF files";
  2598. goto ioerror; //something we don't know about!
  2599. }
  2600. f->aiffchunks = 0;
  2601. if(write_dw_msf(TAG('C','O','M','M'), f)
  2602. || write_dw_msf(18, f)
  2603. #if defined _WIN32
  2604. || (f->fmtchunkoffset = SetFilePointer(f->fileno,0L,NULL,FILE_CURRENT))==0xFFFFFFFF
  2605. || write_w_msf(f->fmtchunkEx.Format.nChannels, f)
  2606. || write_dw_msf(0, f) /* num sample frames */
  2607. || write_w_msf(f->fmtchunkEx.Format.wBitsPerSample, f)
  2608. || write_dw_toex(f->fmtchunkEx.Format.nSamplesPerSec, f) )
  2609. goto ioerror;
  2610. #else
  2611. || fgetpos(f->fileno, &bytepos)
  2612. || write_w_msf(f->fmtchunkEx.Format.nChannels, f)
  2613. || write_dw_msf(0, f) /* num sample frames */
  2614. || write_w_msf(f->fmtchunkEx.Format.wBitsPerSample, f)
  2615. || write_dw_toex(f->fmtchunkEx.Format.nSamplesPerSec, f) )
  2616. goto ioerror;
  2617. f->fmtchunkoffset = bytepos;
  2618. #endif
  2619. //RWD.6.5.99 ADD the PEAK chunk
  2620. if((f->min_header >= SFILE_PEAKONLY) && f->peaks){
  2621. int i,size;
  2622. DWORD now = 0;
  2623. for(i=0;i < channels; i++){
  2624. f->peaks[i].value = 0.0f;
  2625. f->peaks[i].position = 0;
  2626. }
  2627. size = 2 * sizeof(DWORD) + channels * sizeof(CHPEAK);
  2628. if(write_dw_msf(TAG('P','E','A','K'),f)
  2629. || write_dw_msf(size,f)
  2630. #if defined _WIN32
  2631. || ((f->peakchunkoffset = SetFilePointer(f->fileno,0L,NULL, FILE_CURRENT))== 0xFFFFFFFF)
  2632. || write_dw_msf(CURRENT_PEAK_VERSION,f)
  2633. || write_dw_msf(now,f)
  2634. || write_peak_msf(channels,f))
  2635. goto ioerror;
  2636. #else
  2637. || fgetpos(f->fileno, &bytepos)
  2638. || write_dw_msf(CURRENT_PEAK_VERSION,f)
  2639. || write_dw_msf(now,f)
  2640. || write_peak_msf(channels,f))
  2641. goto ioerror;
  2642. f->peakchunkoffset = bytepos;
  2643. #endif
  2644. }
  2645. if(f->min_header >= SFILE_CDP){
  2646. if(write_dw_msf(TAG('A','P','P','L'), f)
  2647. || write_dw_msf(sizeof(DWORD) + PROPCNKSIZE, f)
  2648. || write_dw_msf(TAG('s','f','i','f'), f)
  2649. #if defined _WIN32
  2650. || (f->propoffset = SetFilePointer(f->fileno, 0L,NULL,FILE_CURRENT))==0xFFFFFFFF
  2651. || SetFilePointer(f->fileno,(long)PROPCNKSIZE,NULL,FILE_CURRENT) == 0xFFFFFFFF)
  2652. goto ioerror;
  2653. #else
  2654. || fgetpos(f->fileno, &bytepos)
  2655. || fseek(f->fileno, (long)PROPCNKSIZE, SEEK_CUR) < 0)
  2656. goto ioerror;
  2657. f->propoffset = bytepos;
  2658. #endif
  2659. }
  2660. if(write_dw_msf(TAG('S','S','N','D'), f)
  2661. || write_dw_msf(0, f)
  2662. || write_dw_msf(0, f) /* offset */
  2663. || write_dw_msf(0, f) /* blocksize */
  2664. #if defined _WIN32
  2665. || (f->datachunkoffset = SetFilePointer(f->fileno,0L,NULL,FILE_CURRENT)) == 0xFFFFFFFF)
  2666. goto ioerror;
  2667. #else
  2668. || fgetpos(f->fileno, &bytepos) )
  2669. goto ioerror;
  2670. f->datachunkoffset = bytepos;
  2671. #endif
  2672. if(f->min_header >= SFILE_CDP){
  2673. f->propschanged = 1;
  2674. f->proplim = PROPCNKSIZE;
  2675. }
  2676. f->datachunksize = 0;
  2677. f->extrachunksizes = 0;
  2678. f->header_set = 1;
  2679. return 0;
  2680. /* NOTREACHED */
  2681. ioerror:
  2682. rsferrno = ESFWRERR;
  2683. if(rsferrstr == NULL)
  2684. rsferrstr = "error writing aiff header";
  2685. return 1;
  2686. }
  2687. /*RWD 22:6:2000 now use 'fl32', so the new Cubase will read it!*/
  2688. static int
  2689. wraifchdr(struct sf_file *f,int channels,int srate,int stype)
  2690. {
  2691. DWORD aifcver = AIFC_VERSION_1;
  2692. DWORD ID_compression;
  2693. fpos_t bytepos;
  2694. //assume 32bit floats, but we may be asked to use aifc for integer formats too
  2695. char *str_compressed = (char *) aifc_floatstring;
  2696. int pstring_size = 10;
  2697. rsferrstr = NULL;
  2698. if(stype >= SAMP_MASKED)
  2699. return 1;
  2700. /*RWD Sept 2000: was "ff32!" .*/
  2701. if(stype==SAMP_FLOAT)
  2702. ID_compression = TAG('f','l','3','2');
  2703. /* RWD 06-01-09 TODO: add "in24" type? */
  2704. else {
  2705. ID_compression = TAG('N','O','N','E');
  2706. pstring_size = 16;
  2707. str_compressed = (char *) aifc_notcompressed;
  2708. }
  2709. f->mainchunksize = 0;
  2710. if(write_dw_msf(TAG('F','O','R','M'), f)
  2711. ||write_dw_msf(0, f)
  2712. ||write_dw_msf(TAG('A','I','F','C'), f) )
  2713. goto ioerror;
  2714. f->fmtchunkEx.Format.nChannels = (short)channels;
  2715. f->fmtchunkEx.Format.nSamplesPerSec = srate;
  2716. switch(stype){
  2717. case(SAMP_SHORT):
  2718. f->fmtchunkEx.Format.wBitsPerSample = 16;
  2719. f->fmtchunkEx.Format.nBlockAlign = sizeof(short) * f->fmtchunkEx.Format.nChannels;
  2720. break;
  2721. case(SAMP_FLOAT):
  2722. case(SAMP_LONG):
  2723. f->fmtchunkEx.Format.wBitsPerSample = 32;
  2724. f->fmtchunkEx.Format.nBlockAlign = sizeof(/*long*/int) * f->fmtchunkEx.Format.nChannels;
  2725. break;
  2726. case(SAMP_2024):
  2727. f->fmtchunkEx.Format.wBitsPerSample = 20;
  2728. f->fmtchunkEx.Format.nBlockAlign = 3 * f->fmtchunkEx.Format.nChannels;
  2729. case(SAMP_2424):
  2730. f->fmtchunkEx.Format.wBitsPerSample = 24;
  2731. f->fmtchunkEx.Format.nBlockAlign = 3 * f->fmtchunkEx.Format.nChannels;
  2732. break;
  2733. //NB 2432 format not allowed in AIF file!
  2734. default:
  2735. rsferrstr = "requested sample format not supported by AIFF-C";
  2736. goto ioerror; //something we don't know about!
  2737. }
  2738. f->aiffchunks = 0;
  2739. //write FVER chunk
  2740. if(write_dw_msf(TAG('F','V','E','R'),f)
  2741. || write_dw_msf(4,f)
  2742. || write_dw_msf(aifcver,f))
  2743. goto ioerror;
  2744. //extended COMM chunk...22 bytes plus size of pascal string, rounded
  2745. if(write_dw_msf(TAG('C','O','M','M'), f)
  2746. || write_dw_msf(22 + pstring_size, f)
  2747. #if defined _WIN32
  2748. || (f->fmtchunkoffset = SetFilePointer(f->fileno,0L,NULL,FILE_CURRENT))==0xFFFFFFFF
  2749. || write_w_msf(f->fmtchunkEx.Format.nChannels, f)
  2750. || write_dw_msf(0, f) /* num sample frames */
  2751. || write_w_msf(f->fmtchunkEx.Format.wBitsPerSample, f)
  2752. || write_dw_toex(f->fmtchunkEx.Format.nSamplesPerSec, f) )
  2753. goto ioerror;
  2754. #else
  2755. || fgetpos(f->fileno, &bytepos)
  2756. || write_w_msf(f->fmtchunkEx.Format.nChannels, f)
  2757. || write_dw_msf(0, f) /* num sample frames */
  2758. || write_w_msf(f->fmtchunkEx.Format.wBitsPerSample, f)
  2759. || write_dw_toex(f->fmtchunkEx.Format.nSamplesPerSec, f) )
  2760. goto ioerror;
  2761. f->fmtchunkoffset = bytepos;
  2762. #endif
  2763. //now the special bits...
  2764. if(write_dw_msf(ID_compression,f))
  2765. goto ioerror;
  2766. //the dreaded pascal string...
  2767. if(dowrite(f,str_compressed,pstring_size))
  2768. goto ioerror;
  2769. //RWD.6.5.99 ADD the PEAK chunk
  2770. if((f->min_header >= SFILE_PEAKONLY) && f->peaks){
  2771. int i,size;
  2772. DWORD now = 0;
  2773. for(i=0;i < channels; i++){
  2774. f->peaks[i].value = 0.0f;
  2775. f->peaks[i].position = 0;
  2776. }
  2777. size = 2 * sizeof(DWORD) + channels * sizeof(CHPEAK);
  2778. if(write_dw_msf(TAG('P','E','A','K'),f)
  2779. || write_dw_msf(size,f)
  2780. #if defined _WIN32
  2781. || ((f->peakchunkoffset = SetFilePointer(f->fileno,0L,NULL, FILE_CURRENT))== 0xFFFFFFFF)
  2782. || write_dw_msf(CURRENT_PEAK_VERSION,f)
  2783. || write_dw_msf(now,f)
  2784. || write_peak_msf(channels,f))
  2785. goto ioerror;
  2786. #else
  2787. || fgetpos(f->fileno, &bytepos)
  2788. || write_dw_msf(CURRENT_PEAK_VERSION,f)
  2789. || write_dw_msf(now,f)
  2790. || write_peak_msf(channels,f))
  2791. goto ioerror;
  2792. f->peakchunkoffset = bytepos;
  2793. #endif
  2794. }
  2795. if(f->min_header >= SFILE_CDP){
  2796. if(write_dw_msf(TAG('A','P','P','L'), f)
  2797. || write_dw_msf(sizeof(DWORD) + PROPCNKSIZE, f)
  2798. || write_dw_msf(TAG('s','f','i','f'), f)
  2799. #if defined _WIN32
  2800. || (f->propoffset = SetFilePointer(f->fileno, 0L,NULL,FILE_CURRENT))==0xFFFFFFFF
  2801. || SetFilePointer(f->fileno,(long)PROPCNKSIZE,NULL,FILE_CURRENT) == 0xFFFFFFFF)
  2802. goto ioerror;
  2803. #else
  2804. || fgetpos(f->fileno, &bytepos)
  2805. || fseek(f->fileno, (long)PROPCNKSIZE, SEEK_CUR) < 0)
  2806. goto ioerror;
  2807. f->propoffset = bytepos;
  2808. #endif
  2809. }
  2810. if(write_dw_msf(TAG('S','S','N','D'), f)
  2811. ||write_dw_msf(0, f)
  2812. ||write_dw_msf(0, f) /* offset */
  2813. ||write_dw_msf(0, f) /* blocksize */
  2814. #if defined _WIN32
  2815. ||(f->datachunkoffset = SetFilePointer(f->fileno,0L,NULL,FILE_CURRENT)) == 0xFFFFFFFF)
  2816. goto ioerror;
  2817. #else
  2818. ||fgetpos(f->fileno, &bytepos) )
  2819. goto ioerror;
  2820. f->datachunkoffset = bytepos;
  2821. #endif
  2822. if(f->min_header >= SFILE_CDP){
  2823. f->propschanged = 1;
  2824. f->proplim = PROPCNKSIZE;
  2825. }
  2826. f->datachunksize = 0;
  2827. f->extrachunksizes = 0;
  2828. f->header_set = 1;
  2829. return 0;
  2830. /* NOTREACHED */
  2831. ioerror:
  2832. rsferrno = ESFWRERR;
  2833. if(rsferrstr==NULL)
  2834. rsferrstr = "error writing aiff-c header";
  2835. return 1;
  2836. }
  2837. /*
  2838. * Initialization routines
  2839. */
  2840. static void
  2841. rsffinish(void)
  2842. {
  2843. int i;
  2844. for(i = 0; i < SF_MAXFILES; i++)
  2845. if(sf_files[i] != 0)
  2846. sfclose(i+SFDBASE);
  2847. #ifdef ENABLE_PVX
  2848. pvsys_release();
  2849. #endif
  2850. #ifdef _WIN32
  2851. if(CDP_COM_READY){
  2852. COMclose();
  2853. CDP_COM_READY = 0;
  2854. }
  2855. #endif
  2856. }
  2857. int
  2858. sflinit(const char *name)
  2859. {
  2860. int i;
  2861. #if defined ENABLE_PVX
  2862. init_pvsys();
  2863. #endif
  2864. for(i = 0; i < SF_MAXFILES; i++)
  2865. sf_files[i] = 0;
  2866. atexit(rsffinish);
  2867. if(sizeof(DWORD) != 4 || sizeof(WORD) != 2) {
  2868. rsferrno = ESFBADPARAM;
  2869. rsferrstr = "internal: sizeof(WORD) != 2 or sizeof(DWORD) != 4";
  2870. return -1;
  2871. }
  2872. #ifdef _WIN32
  2873. //alternative is to set CDP_COM_READY entirely in shortcuts.c
  2874. #ifdef _DEBUG
  2875. assert(!CDP_COM_READY);
  2876. #endif
  2877. CDP_COM_READY = COMinit(); //need COM to read shortcuts
  2878. #endif
  2879. return 0;
  2880. }
  2881. /*
  2882. * Misc other stuff
  2883. */
  2884. #if 0
  2885. void
  2886. sffinish()
  2887. {
  2888. /* leave everything to atexit! */
  2889. }
  2890. #endif
  2891. char *
  2892. sfgetbigbuf(int *secsize)
  2893. {
  2894. char *mem = (char *) malloc(100*SECSIZE);
  2895. *secsize = (mem == 0) ? 0 : 100;
  2896. return mem;
  2897. }
  2898. void
  2899. sfperror(const char *s)
  2900. {
  2901. if(s == 0)
  2902. s = "sound filing system";
  2903. if(*s != '\0')
  2904. fprintf(stderr, "%s: %s\n", s, rsferrstr);
  2905. else
  2906. fprintf(stderr, "%s\n", rsferrstr);
  2907. }
  2908. char *
  2909. sferrstr(void)
  2910. {
  2911. return rsferrstr;
  2912. }
  2913. int
  2914. sferrno(void)
  2915. {
  2916. return rsferrno;
  2917. }
  2918. int
  2919. sfsetprefix(char *path)
  2920. {
  2921. /* the set prefix call is simply ignored - for now */
  2922. return 0;
  2923. }
  2924. void
  2925. sfgetprefix(char *path)
  2926. {
  2927. path[0] = '\0'; /* signal that no prefix is set */
  2928. }
  2929. /*
  2930. * allocate/de-allocate file numbers
  2931. */
  2932. static int allocsffile(char *filename)
  2933. {
  2934. int i;
  2935. int first_i = -1;
  2936. /*#if defined CDP97 && defined _WIN32*/
  2937. int refcnt98 = 1; //RWD incr refcnt for THIS file, if we have previously opened it
  2938. /*#endif*/
  2939. for(i = 0; i < SF_MAXFILES; i++)
  2940. if(sf_files[i] == 0) {
  2941. if(first_i < 0)
  2942. first_i = i;
  2943. }
  2944. //RWD98 excluding the return ~seems~ to be all thats needed to get multiple opens!
  2945. else if(_stricmp(sf_files[i]->filename, filename) == 0) {/* not quite right! */
  2946. sf_files[i]->refcnt++;
  2947. refcnt98++; //for THIS file
  2948. //return i;
  2949. }
  2950. if(first_i < 0) {
  2951. rsferrno = ESFNOSFD;
  2952. rsferrstr = "Too many Sfiles are open";
  2953. free(filename);
  2954. return -1;
  2955. }
  2956. if((sf_files[first_i] = ALLOC(struct sf_file)) == 0) {
  2957. rsferrno = ESFNOMEM;
  2958. rsferrstr = "No memory for open SFfile";
  2959. free(filename);
  2960. return -1;
  2961. }
  2962. memset(sf_files[first_i],0,sizeof(struct sf_file)); // RWD defensive etc
  2963. sf_files[first_i]->refcnt = refcnt98;
  2964. //sf_files[first_i]->refcnt = 1; //RWD.6.98 restore this to restore old behaviour
  2965. sf_files[first_i]->filename = filename;
  2966. sf_files[first_i]->props = 0;
  2967. sf_files[first_i]->proplim = 0;
  2968. sf_files[first_i]->curpropsize = 0;
  2969. sf_files[first_i]->propschanged = 0;
  2970. sf_files[first_i]->aiffchunks = 0;
  2971. sf_files[first_i]->peaktime = 0;
  2972. POS64(sf_files[first_i]->peakchunkoffset) = 0;
  2973. POS64(sf_files[first_i]->factchunkoffset) = 0;
  2974. POS64(sf_files[first_i]->datachunkoffset) = 0;
  2975. sf_files[first_i]->peaks = NULL;
  2976. sf_files[first_i]->bitmask = 0xffffffff;
  2977. sf_files[first_i]->fmtchunkEx.dwChannelMask = 0;
  2978. sf_files[first_i]->chformat = STDWAVE;
  2979. sf_files[first_i]->min_header = SFILE_CDP;
  2980. #ifdef ENABLE_PVX
  2981. sf_files[first_i]->pvxprops = NULL;
  2982. #endif
  2983. return first_i;
  2984. }
  2985. static void
  2986. freesffile(int i)
  2987. {
  2988. struct property *pp = sf_files[i]->props;
  2989. struct aiffchunk *ap = sf_files[i]->aiffchunks;
  2990. while(pp != /* 0 */ NULL) {
  2991. struct property *pnext = pp->next;
  2992. free(pp->name);
  2993. free(pp->data);
  2994. free(pp);
  2995. pp = pnext;
  2996. }
  2997. while(ap != /* 0 */ NULL) {
  2998. struct aiffchunk *anext = ap->next;
  2999. free(ap->buf);
  3000. free(ap);
  3001. ap = anext;
  3002. }
  3003. free(sf_files[i]->filename);
  3004. //RWD.6.5.99
  3005. if(sf_files[i]->peaks != NULL)
  3006. free(sf_files[i]->peaks);
  3007. #ifdef ENABLE_PVX
  3008. if(sf_files[i]->pvxprops != NULL)
  3009. free(sf_files[i]->pvxprops);
  3010. #endif
  3011. free(sf_files[i]);
  3012. sf_files[i] = /* 0 */ NULL;
  3013. }
  3014. #ifdef unix
  3015. #define PATH_SEP '/'
  3016. #else
  3017. #define PATH_SEP '\\'
  3018. #endif
  3019. //RWD: the environment var code prevents use of a defined analysis file extension
  3020. //in addition to CDP_SOUND_EXT ...
  3021. //RWD98 now declared static at top of file
  3022. /*RWD for DevCPp*/
  3023. #ifndef _MAX_PATH
  3024. #define _MAX_PATH (255)
  3025. #endif
  3026. static enum sndfiletype
  3027. gettypefromname98(const char *path)
  3028. {
  3029. #ifdef NOTDEF
  3030. char *eos = &path[strlen(path)]; /* points to the null byte */
  3031. char *lastsl = strrchr(path, PATH_SEP);
  3032. #else
  3033. //RWD98: use hackable local copy of path, to check for WIN32 shortcut
  3034. //this bit general, though
  3035. char *eos, *lastsl;
  3036. char copypath[_MAX_PATH];
  3037. int len;
  3038. copypath[0] = '\0';
  3039. strcpy(copypath,path);
  3040. len = strlen(copypath);
  3041. eos = &copypath[len];
  3042. lastsl = strrchr(copypath,PATH_SEP);
  3043. #endif
  3044. // if(lastsl == 0) //RWD 2022 this fails if path is in current directory, no separator present
  3045. //abort();
  3046. // return unknown_wave; //RWD.1.99
  3047. #ifdef _WIN32
  3048. //it it a shortcut?
  3049. if(_stricmp(eos-4, ".lnk")==0) {
  3050. copypath[len-4] = '\0'; //cut away link extension
  3051. eos -= 4; //step past the ext, we should be left with a kosher sfilename
  3052. }
  3053. #endif
  3054. if(eos-4 > lastsl && _stricmp(eos-4, ".wav") == 0)
  3055. return riffwav;
  3056. else if(eos-4 > lastsl && _stricmp(eos-4, ".aif") == 0)
  3057. return eaaiff;
  3058. else if(eos-5 > lastsl && _stricmp(eos-5, ".aiff") == 0)
  3059. return eaaiff;
  3060. //Recognize AIF-C files: use separate sndfiletype for this?
  3061. else if(eos-4 > lastsl && _stricmp(eos-4,".afc") == 0)
  3062. return aiffc;
  3063. else if(eos-4 > lastsl && _stricmp(eos-4,".aic") == 0)
  3064. return aiffc;
  3065. else if(eos-5 > lastsl && _stricmp(eos-5,".aifc") == 0)
  3066. return aiffc;
  3067. /* FILE_AMB_SUPPORT */
  3068. else if(eos-4 > lastsl && _stricmp(eos-4, ".amb") == 0)
  3069. return riffwav;
  3070. else if(eos-5 > lastsl && _stricmp(eos-5, ".ambi") == 0) //RWD April 2006 was -4 !
  3071. return riffwav;
  3072. else if(eos-5 > lastsl && _stricmp(eos-5, ".wxyz") == 0)
  3073. return riffwav;
  3074. //CDP97: recognise .ana as signifying analysis file - find out later whether wav or aiff
  3075. /* 4:2001 added revised extensions for and evl; lose fmt and env in time */
  3076. else if(_stricmp(eos-4, ".ana") == 0 //analysis file
  3077. || _stricmp(eos-4,".fmt") == 0 //formant file
  3078. || _stricmp(eos-4,".for") == 0
  3079. || _stricmp(eos-4,".frq") == 0 // pitch file
  3080. || _stricmp(eos-4,".env") == 0 // binary envelope
  3081. || _stricmp(eos-4,".evl") == 0
  3082. || _stricmp(eos-4,".trn") == 0 ) // transposition file
  3083. return cdpfile;
  3084. #ifdef ENABLE_PVX
  3085. else if(_stricmp(eos-4,".pvx") == 0 ) //PVOCEX analysis file
  3086. return pvxfile;
  3087. #endif
  3088. return unknown_wave;
  3089. }
  3090. //if a cdpfile - what format is it?
  3091. //RWD TODO: rewrite this with error retval, or at least add sferrstr message if bad seek
  3092. /* RWD NB: would need to drill further into header to discover a pvx file - maybe a "findGuid" function? */
  3093. /* but currently this leaves the file open for further parsing, currently pvx handled separately */
  3094. static enum sndfiletype
  3095. gettypefromfile(struct sf_file *f)
  3096. {
  3097. DWORD tag1,tag2,size;
  3098. enum sndfiletype type = unknown_wave;
  3099. if(read_dw_msf(&tag1, f) || read_dw_lsf(&size, f) || read_dw_msf(&tag2,f)) {
  3100. #if defined _WIN32
  3101. if(SetFilePointer(f->fileno,0,NULL,FILE_BEGIN)==0xFFFFFFFF)
  3102. #else
  3103. if(fseek(f->fileno,0,SEEK_SET) < 0)
  3104. #endif
  3105. return unknown_wave;
  3106. }
  3107. else if(tag1 == TAG('R','I','F','F') && tag2 == TAG('W','A','V','E')){
  3108. type = riffwav;
  3109. }
  3110. else if(tag1 == TAG('F','O','R','M') && tag2 == TAG('A','I','F','F')){
  3111. type = eaaiff;
  3112. }
  3113. //RWD.1.99 support aifc files as well
  3114. else if(tag1 == TAG('F','O','R','M') && tag2 == TAG('A','I','F','C')){
  3115. type = aiffc;
  3116. }
  3117. #if defined _WIN32
  3118. if(SetFilePointer(f->fileno,0,NULL,FILE_BEGIN)==0xFFFFFFFF)
  3119. #else
  3120. if(fseek(f->fileno,0,SEEK_SET) < 0)
  3121. #endif
  3122. return unknown_wave;
  3123. return type;
  3124. }
  3125. //RWD.6.98 when tested, add shortcuts code...
  3126. static char *
  3127. mksfpath(const char *name)
  3128. {
  3129. char *errormsg;
  3130. char *path = _fullpath(NULL, name, 0);
  3131. enum sndfiletype filetype = unknown_wave; //RWD 2015
  3132. if(path == NULL) {
  3133. rsferrno = ESFBADPARAM;
  3134. rsferrstr = "can't find full path for soundfile - bad drive?";
  3135. //#ifdef unix
  3136. // printf("realpath failed:errno = %d:%s\n",errno,strerror(errno));
  3137. //#endif
  3138. return NULL;
  3139. }
  3140. #ifdef _WIN32
  3141. //if its a shortcut, strip off the link extension: sfopen will try normal open first
  3142. {
  3143. int len;
  3144. char *eos;
  3145. len = strlen(path);
  3146. eos = &path[len-4];
  3147. if(_stricmp(eos,".lnk")==0)
  3148. path[len-4] = '\0';
  3149. }
  3150. #endif
  3151. /* RWD March 2014 make this optional! */
  3152. filetype = gettypefromname98(path);
  3153. if( filetype == unknown_wave) {
  3154. char *newpath;
  3155. char *ext;
  3156. char *ext_default = "wav";
  3157. // RWD MAR 2015 we may have unset CDP_SOUND_EXT, but not removed it completely!
  3158. if((ext = getenv("CDP_SOUND_EXT")) == NULL || strlen(ext) == 0 ) {
  3159. //rsferrno = ESFBADPARAM;
  3160. //rsferrstr = "unknown sound file type - extension not set";
  3161. //free(path);
  3162. //return NULL;
  3163. ext = ext_default;
  3164. }
  3165. if(_stricmp(ext, "wav") != 0
  3166. &&_stricmp(ext, "aif") != 0
  3167. &&_stricmp(ext, "aiff") != 0
  3168. &&_stricmp(ext,"afc") != 0 //Apple...
  3169. &&_stricmp(ext,"aic") != 0 //Csound uses this form
  3170. &&_stricmp(ext,"aifc") !=0) {
  3171. rsferrno = ESFBADPARAM;
  3172. rsferrstr = "unknown sound file type - bad CDP_SOUND_EXT setting";
  3173. free(path);
  3174. return NULL;
  3175. }
  3176. if((newpath = (char *) malloc(strlen(path) + strlen(ext) + 2)) == 0) {
  3177. rsferrno = ESFNOMEM;
  3178. rsferrstr = "can't get memory for full path of soundfile";
  3179. free(path);
  3180. return NULL;
  3181. }
  3182. strcpy(newpath, path);
  3183. strcat(newpath, ".");
  3184. strcat(newpath, ext);
  3185. free(path);
  3186. path = newpath;
  3187. }
  3188. if((errormsg = legalfilename(path)) != 0) {
  3189. rsferrno = ESFBADPARAM;
  3190. rsferrstr = errormsg;
  3191. free(path);
  3192. return NULL;
  3193. }
  3194. return path;
  3195. }
  3196. /*
  3197. * public sf routines
  3198. */
  3199. //RWD.6.98 TODO when tested, add all the file-sharing code
  3200. // best to #ifdef the revised function in as a block...
  3201. /* RWD TOD 2022: get rid of all the ifdefs, make separate whole functions */
  3202. #if 0
  3203. int
  3204. sfopen(const char *name)
  3205. {
  3206. int i, rc;
  3207. struct sf_file *f;
  3208. char *sfpath;
  3209. #if defined _WIN32
  3210. DWORD access = GENERIC_WRITE | GENERIC_READ; //assumeed for first open (eg for maxsamp...)
  3211. //seems I need to set write sharing so some other process can write...
  3212. DWORD sharing = FILE_SHARE_READ; //for first open
  3213. #else
  3214. char *faccess = "r+";
  3215. #endif
  3216. //#ifdef _WIN32
  3217. char newpath[_MAX_PATH];
  3218. newpath[0] = '\0';
  3219. //#endif
  3220. if((sfpath = mksfpath(name)) == NULL)
  3221. return -1;
  3222. if((i = allocsffile(sfpath)) < 0)
  3223. return -1;
  3224. f = sf_files[i];
  3225. //#ifdef NOTDEF
  3226. //this may not be needed after all: can't really display a file while is is being written to...
  3227. if(f->refcnt > 1) {
  3228. # if defined _WIN32
  3229. access = GENERIC_READ;
  3230. sharing = FILE_SHARE_WRITE | FILE_SHARE_READ; //repeat opens MUST allow first open to write!
  3231. # else
  3232. //faccess = "r"; /*RWD 2010 allow this ?? */
  3233. rsferrno = ESFNOTOPEN;
  3234. rsferrstr = "Can't open file more than once - yet!";
  3235. freesffile(i);
  3236. return -1;
  3237. # endif
  3238. }
  3239. //#endif
  3240. f->readonly = 0;
  3241. #ifdef _WIN32
  3242. f->is_shortcut = 0;
  3243. #endif
  3244. //first, try normal open as rd/wr
  3245. #if defined _WIN32
  3246. if((f->fileno = CreateFile(f->filename,access,sharing,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL)) == INVALID_HANDLE_VALUE)
  3247. #else
  3248. if((f->fileno = fopen(f->filename, faccess)) == NULL)
  3249. #endif
  3250. {
  3251. #if defined _WIN32
  3252. DWORD w_errno = GetLastError();
  3253. #endif
  3254. rsferrno = ESFNOTFOUND;
  3255. #if defined _WIN32
  3256. if(w_errno != ERROR_FILE_NOT_FOUND){
  3257. #else
  3258. if(errno != ENOENT){ //won't exist if its actually a shortcut
  3259. #endif
  3260. #if defined _WIN32
  3261. if(w_errno == ERROR_INVALID_NAME) {
  3262. #else
  3263. if(errno == EINVAL) {
  3264. #endif
  3265. rsferrstr = "Illegal filename";
  3266. freesffile(i);
  3267. return -1;
  3268. }
  3269. #if defined _WIN32
  3270. if(w_errno != ERROR_ACCESS_DENIED) {
  3271. #else
  3272. if(errno != EACCES) {
  3273. #endif
  3274. rsferrstr = "SFile not found";
  3275. freesffile(i);
  3276. return -1;
  3277. }
  3278. }
  3279. }
  3280. /* block below is ONLY for Windows */
  3281. #ifdef _WIN32
  3282. //try a shortcut to rd/wr file...
  3283. if(f->fileno == INVALID_HANDLE_VALUE){
  3284. if(
  3285. (CDP_COM_READY) &&
  3286. (getAliasName(f->filename,newpath)) &&
  3287. //# ifdef CDP99
  3288. ((f->fileno = CreateFile(newpath,access,sharing,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL)) == INVALID_HANDLE_VALUE)
  3289. //# else
  3290. // ((f->fileno = open(newpath, _O_BINARY|_O_RDWR) ) < 0)
  3291. //# endif
  3292. ) {
  3293. //good link, but still no open...
  3294. //# ifdef CDP99
  3295. DWORD w_errno = GetLastError();
  3296. rsferrno = ESFNOTFOUND;
  3297. if(w_errno == ERROR_INVALID_NAME) {
  3298. //# else
  3299. // rsferrno = ESFNOTFOUND;
  3300. // if(errno == EINVAL) {
  3301. //# endif
  3302. rsferrstr = "Illegal filename";
  3303. freesffile(i);
  3304. return -1;
  3305. }
  3306. //# ifdef CDP99
  3307. if(w_errno != ERROR_ACCESS_DENIED) {
  3308. //# else
  3309. // if(errno != EACCES) {
  3310. //# endif
  3311. rsferrstr = "SFile not found";
  3312. freesffile(i);
  3313. return -1;
  3314. }
  3315. }
  3316. }
  3317. #endif
  3318. /* "normal" file open code here */
  3319. //must be rdonly, try normal open or shortcut
  3320. #if defined _WIN32
  3321. if(f->fileno== INVALID_HANDLE_VALUE){
  3322. #else
  3323. if(f->fileno==NULL){
  3324. #endif
  3325. #ifdef _WIN32
  3326. if(
  3327. ((f->fileno = CreateFile(f->filename, GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_READONLY,NULL)) == INVALID_HANDLE_VALUE)
  3328. && (!((CDP_COM_READY) || (getAliasName(f->filename,newpath)))
  3329. || ((f->fileno = CreateFile(newpath, GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_READONLY,NULL)) == INVALID_HANDLE_VALUE)
  3330. )
  3331. #else
  3332. if(
  3333. ((f->fileno = fopen(f->filename, "r")) == NULL)
  3334. )
  3335. #endif
  3336. {
  3337. rsferrstr = "SFile not found";
  3338. freesffile(i);
  3339. return -1;
  3340. }
  3341. f->readonly = 1;
  3342. }
  3343. #ifdef _WIN32
  3344. if(strlen(newpath) >0) {
  3345. f->filename[0] = '\0';
  3346. f->is_shortcut = 1;
  3347. strcpy(f->filename,newpath); //filename will be freed eventually; don't copy pointers
  3348. }
  3349. #endif
  3350. switch(f->filetype = gettypefromfile(f)) {
  3351. case riffwav:
  3352. rc = rdwavhdr(f);
  3353. break;
  3354. case eaaiff:
  3355. rc = rdaiffhdr(f);
  3356. break;
  3357. case aiffc:
  3358. rc = rdaifchdr(f);
  3359. break;
  3360. default:
  3361. rsferrno = ESFNOSTYPE;
  3362. rsferrstr = "Internal error: can't find file type";
  3363. rc = 1;
  3364. }
  3365. if(rc) {
  3366. freesffile(i);
  3367. return -1;
  3368. }
  3369. f->infochanged = 0;
  3370. f->todelete = 0;
  3371. f->sizerequested = ES_EXIST;
  3372. f->curpos = 0;
  3373. return i+SFDBASE;
  3374. }
  3375. #endif
  3376. #ifdef ENABLE_PVX
  3377. /* return -1 for error in fd, 0 for false (i.e. is sfile or .ana file), 1 for true */
  3378. int sf_ispvx(int sfd)
  3379. {
  3380. struct sf_file *f;
  3381. if((f = findfile(sfd)) == 0)
  3382. return -1;
  3383. return (f->filetype == pvxfile);
  3384. }
  3385. /* pvx file id can be 0, so that can't be used to flag error */
  3386. int get_pvxfd(int sfd ,PVOCDATA *pvxdata ){
  3387. struct sf_file *f;
  3388. int rc = -1;
  3389. if((f = findfile(sfd)) == 0)
  3390. return rc;
  3391. else if((f->filetype == pvxfile) && (f->pvxprops != NULL)) {
  3392. rc = f->pvxfileno;
  3393. if(pvxdata != NULL) {
  3394. //memcpy((char*) pvxdata,(char*) &f->pvxprops,sizeof(PVOCDATA));
  3395. pvxdata->wWordFormat = f->pvxprops->wWordFormat;
  3396. pvxdata->wAnalFormat = f->pvxprops->wAnalFormat;
  3397. pvxdata->wSourceFormat = f->pvxprops->wSourceFormat;
  3398. pvxdata->wWindowType = f->pvxprops->wWindowType;
  3399. pvxdata->nAnalysisBins = f->pvxprops->nAnalysisBins;
  3400. pvxdata->dwWinlen = f->pvxprops->dwWinlen;
  3401. pvxdata->dwOverlap = f->pvxprops->dwOverlap;
  3402. pvxdata->dwFrameAlign = f->pvxprops->dwFrameAlign;
  3403. pvxdata->fAnalysisRate = f->pvxprops->fAnalysisRate;
  3404. pvxdata->fWindowParam = f->pvxprops->fWindowParam;
  3405. }
  3406. }
  3407. return rc;
  3408. }
  3409. // this needs to be declared in sffuncs.h - accessible by snd.c, but not durectly to app code
  3410. /* currently NOTUSED, ditto snd_getpvxfno in snd.c */
  3411. int getpvxfno(int sfd){
  3412. struct sf_file *f;
  3413. int rc = 0;
  3414. if((f = findfile(sfd)) == 0)
  3415. rc = -1;
  3416. else if(f->pvxprops == NULL) //bad call to getpvxfno
  3417. rc = -1;
  3418. else
  3419. rc = f->pvxfileno;
  3420. return rc;
  3421. }
  3422. #endif
  3423. //RWD.9.98 new version to control access
  3424. int
  3425. sfopenEx(const char *name, unsigned int access)
  3426. {
  3427. int i, rc;
  3428. struct sf_file *f;
  3429. char *sfpath;
  3430. char newpath[_MAX_PATH];
  3431. newpath[0] = '\0';
  3432. if((sfpath = mksfpath(name)) == NULL)
  3433. return -1;
  3434. if((i = allocsffile(sfpath)) < 0)
  3435. return -1;
  3436. #ifdef ENABLE_PVX
  3437. # ifdef _DEBUG
  3438. //fprintf(stderr,"sfopenEx: opened in sf_sfiles[%d]\n",i);
  3439. # endif
  3440. f = sf_files[i];
  3441. f->readonly = 0;
  3442. f->is_shortcut = 0;
  3443. #endif
  3444. #ifdef ENABLE_PVX
  3445. // RWD just cheat for now, until it's all working...
  3446. if(gettypefromname98(name) == pvxfile){
  3447. int rc = 0;
  3448. PVOCDATA pvxdata;
  3449. WAVEFORMATEX wftx;
  3450. // setup property block
  3451. # ifdef _DEBUG
  3452. assert(f->pvxprops == NULL);
  3453. assert(f->curpropsize == 0);
  3454. assert(f->props == NULL);
  3455. # endif
  3456. f->filetype = pvxfile;
  3457. f->pvxprops = calloc(1,sizeof(PVOCDATA));
  3458. rc = pvoc_openfile(name,&pvxdata, &wftx);
  3459. if(rc >= 0) {
  3460. memcpy(f->pvxprops,&pvxdata, sizeof(PVOCDATA));
  3461. memcpy(&(f->fmtchunkEx.Format), &wftx, sizeof(WAVEFORMATEX));
  3462. /* in PVX, Format contains details of the source soundfile for this analysis file (original sampsize etc
  3463. * this has to be converted into the relevant SFPROPS fields,
  3464. * and then we have to reconvert Format into what would be obtained from a CDP .ana file.
  3465. * e.g. must be 32bit floats, srate is (int) analysis rate
  3466. */
  3467. //TODO: get datachunk info from header to complete fields in f...which will help dirsf show good numbers.
  3468. f->datachunksize = pvoc_getdatasize_bytes(rc);
  3469. if(pvx_createprops(f) < 0){
  3470. free(f->pvxprops);
  3471. f->pvxprops = NULL;
  3472. return -1;
  3473. }
  3474. # ifdef _DEBUG
  3475. // fprintf(stderr,"sfopenEx: opened pvx file %s - chans = %d\n", name, f->fmtchunkEx.Format.nChannels);
  3476. # endif
  3477. f->fmtchunkEx.Format.nSamplesPerSec = (int) pvxdata.fAnalysisRate;
  3478. f->fmtchunkEx.Format.nChannels = pvxdata.nAnalysisBins * 2;
  3479. f->fmtchunkEx.Format.wBitsPerSample = 32;
  3480. f->fmtchunkEx.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
  3481. f->fmtchunkEx.Format.nBlockAlign = f->fmtchunkEx.Format.nChannels * sizeof(float);
  3482. f->fmtchunkEx.Format.nAvgBytesPerSec =f->fmtchunkEx.Format.nBlockAlign * f->fmtchunkEx.Format.nSamplesPerSec;
  3483. # ifdef _DEBUG
  3484. // fprintf(stderr,"sfopenEx: opened pvx file %s - chans = %d\n", name, f->fmtchunkEx.Format.nChannels);
  3485. # endif
  3486. f->min_header = SFILE_ANAL; // RWD: may not be needed in this case...?
  3487. f->pvxfileno = rc;
  3488. f->infochanged = 0;
  3489. f->todelete = 0;
  3490. f->sizerequested = ES_EXIST;
  3491. f->curpos = 0;
  3492. //RWD: can't decide whether to fill in datachunksize too for full sf mimicry ...
  3493. // don't really want snd funcs to depend on that if it can be avoided
  3494. // if(access == CDP_OPEN_RDONLY)
  3495. f->readonly = 1;
  3496. return i + SFDBASE; // should be fine, we will always check for pvx file
  3497. }
  3498. else {
  3499. # ifdef _DEBUG
  3500. // fprintf(stderr, "sfopenEx: failed to open pvocex file %s\n", name);
  3501. # endif
  3502. free(f->pvxprops);
  3503. f->pvxprops = NULL;
  3504. rsferrstr = "PVX file not found";
  3505. freesffile(i);
  3506. return -1;
  3507. }
  3508. }
  3509. #endif
  3510. /* non-PVX from here */
  3511. if(access == CDP_OPEN_RDONLY){
  3512. #if defined _WIN32
  3513. if(((f->fileno = CreateFile(f->filename, GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_READONLY,NULL)) == INVALID_HANDLE_VALUE)
  3514. #else
  3515. if(((f->fileno = fopen(f->filename, "r")) == NULL)
  3516. #endif
  3517. && ((!CDP_COM_READY)
  3518. || (!getAliasName(f->filename,newpath))
  3519. #if defined _WIN32
  3520. || ((f->fileno = CreateFile(newpath, GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_READONLY,NULL)) == INVALID_HANDLE_VALUE)
  3521. #else
  3522. || ((f->fileno = fopen(newpath, "r") ) == NULL)
  3523. #endif
  3524. )){
  3525. rsferrstr = "SFile not found";
  3526. freesffile(i);
  3527. return -1;
  3528. }
  3529. f->readonly = 1;
  3530. }
  3531. else {
  3532. // normal open as rd/wr
  3533. #if defined _WIN32
  3534. DWORD w_errno;
  3535. if((f->fileno = CreateFile(f->filename, GENERIC_READ | GENERIC_WRITE,
  3536. FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_READONLY,NULL)) == INVALID_HANDLE_VALUE) {
  3537. #else
  3538. if((f->fileno = fopen(f->filename, "r+")) == NULL ) {
  3539. #endif
  3540. rsferrno = ESFNOTFOUND;
  3541. #if defined _WIN32
  3542. w_errno= GetLastError();
  3543. if(w_errno != ERROR_FILE_NOT_FOUND){
  3544. #else
  3545. if(errno != ENOENT){ //won't exist if its actually a shortcut
  3546. #endif
  3547. #if defined _WIN32
  3548. if(w_errno == ERROR_INVALID_NAME) {
  3549. #else
  3550. if(errno == EINVAL) {
  3551. #endif
  3552. rsferrstr = "Illegal filename";
  3553. freesffile(i);
  3554. return -1;
  3555. }
  3556. #if defined _WIN32
  3557. if(w_errno != ERROR_ACCESS_DENIED) {
  3558. #else
  3559. if(errno != EACCES) {
  3560. #endif
  3561. rsferrstr = "SFile not found";
  3562. freesffile(i);
  3563. return -1;
  3564. }
  3565. }
  3566. }
  3567. //try a shortcut to rd/wr file...
  3568. # ifdef _WIN32
  3569. if(f->fileno == INVALID_HANDLE_VALUE){
  3570. # else
  3571. if(f->fileno == NULL){
  3572. # endif
  3573. if(
  3574. (CDP_COM_READY) &&
  3575. (getAliasName(f->filename,newpath)) &&
  3576. #if defined _WIN32
  3577. ((f->fileno = CreateFile(newpath, GENERIC_READ | GENERIC_WRITE,
  3578. FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_READONLY,NULL)) == INVALID_HANDLE_VALUE)
  3579. #else
  3580. ((f->fileno = fopen(newpath, "r+") ) == NULL)
  3581. #endif
  3582. ) {
  3583. //good link, but still no open...
  3584. rsferrno = ESFNOTFOUND;
  3585. #if defined _WIN32
  3586. if(w_errno == ERROR_INVALID_NAME) {
  3587. #else
  3588. if(errno == EINVAL) {
  3589. #endif
  3590. rsferrstr = "Illegal filename";
  3591. freesffile(i);
  3592. return -1;
  3593. }
  3594. #if defined _WIN32
  3595. if(w_errno != ERROR_ACCESS_DENIED) {
  3596. #else
  3597. if(errno != EACCES) {
  3598. #endif
  3599. rsferrstr = "SFile not found";
  3600. freesffile(i);
  3601. return -1;
  3602. }
  3603. }
  3604. }
  3605. #if defined _WIN32
  3606. if(f->fileno== INVALID_HANDLE_VALUE){
  3607. #else
  3608. if(f->fileno == NULL){
  3609. #endif
  3610. rsferrstr = "SFile not found";
  3611. freesffile(i);
  3612. return -1;
  3613. }
  3614. }
  3615. #ifdef _WIN32
  3616. if(strlen(newpath) >0) {
  3617. f->filename[0] = '\0';
  3618. f->is_shortcut = 1;
  3619. strcpy(f->filename,newpath); //filename will be freed eventually; don't copy pointers
  3620. }
  3621. #endif
  3622. switch(f->filetype = gettypefromfile(f)) {
  3623. case riffwav:
  3624. rc = rdwavhdr(f);
  3625. break;
  3626. case eaaiff:
  3627. rc = rdaiffhdr(f);
  3628. break;
  3629. case aiffc:
  3630. rc = rdaifchdr(f);
  3631. break;
  3632. default:
  3633. rsferrno = ESFNOSTYPE;
  3634. rsferrstr = "Internal error: can't find file type";
  3635. rc = 1;
  3636. }
  3637. if(rc) {
  3638. freesffile(i);
  3639. return -1;
  3640. }
  3641. f->infochanged = 0;
  3642. f->todelete = 0;
  3643. f->sizerequested = ES_EXIST;
  3644. f->curpos = 0;
  3645. return i+SFDBASE;
  3646. }
  3647. static struct sf_file *
  3648. findfile(int sfd)
  3649. {
  3650. sfd -= SFDBASE;
  3651. if(sfd < 0 || sfd >= SF_MAXFILES || sf_files[sfd] == 0) {
  3652. rsferrno = ESFNOTOPEN;
  3653. rsferrstr = "soundfile descriptor does not refer to an open soundfile";
  3654. return 0;
  3655. }
  3656. return sf_files[sfd];
  3657. }
  3658. static int
  3659. comparewithlist(const char *list, const char *name)
  3660. {
  3661. size_t len = strlen(name);
  3662. for(;;) {
  3663. if(_strnicmp(list, name, len) == 0
  3664. &&(list[len] == '\0' || list[len] == ','))
  3665. return 1;
  3666. if((list = strchr(list, ',')) == 0)
  3667. break;
  3668. list++;
  3669. }
  3670. return 0;
  3671. }
  3672. /* RWD note: used only for create functions */
  3673. #if defined _WIN32
  3674. static HANDLE doopen(const char *name, const char *origname,cdp_create_mode mode)
  3675. {
  3676. char *ovrflg;
  3677. HANDLE rc;
  3678. DWORD access,sharing,attrib,w_errno;
  3679. access = GENERIC_READ | GENERIC_WRITE;
  3680. sharing = FILE_SHARE_READ;
  3681. attrib = FILE_ATTRIBUTE_NORMAL;
  3682. if(mode==CDP_CREATE_TEMPORARY){
  3683. sharing = 0;
  3684. attrib = FILE_ATTRIBUTE_TEMPORARY
  3685. | FILE_ATTRIBUTE_HIDDEN
  3686. | FILE_FLAG_DELETE_ON_CLOSE;
  3687. }
  3688. if(mode==CDP_CREATE_RDONLY)
  3689. attrib = FILE_ATTRIBUTE_READONLY;
  3690. if((rc = CreateFile(name, access,sharing,NULL,CREATE_NEW,attrib,NULL)) != INVALID_HANDLE_VALUE)
  3691. return rc;
  3692. w_errno = GetLastError();
  3693. if(!(w_errno == ERROR_FILE_EXISTS || w_errno==ERROR_ALREADY_EXISTS))
  3694. return rc;
  3695. if(mode==CDP_CREATE_NORMAL){
  3696. if((ovrflg = getenv("CDP_OVERWRITE_FILE")) == 0)
  3697. return rc;
  3698. if(strcmp(ovrflg, "*") != 0
  3699. &&!comparewithlist(ovrflg, origname))
  3700. return rc;
  3701. return CreateFile(name, access,sharing,NULL,CREATE_ALWAYS,attrib,NULL);
  3702. }
  3703. else
  3704. return rc;
  3705. }
  3706. #else
  3707. static FILE* doopen(const char *name, const char *origname,cdp_create_mode mode)
  3708. {
  3709. char *ovrflg;
  3710. FILE* fp = NULL;
  3711. //RWD set modeflags here to allow setting a temporary file in CDP97
  3712. //int exclmode,truncmode;
  3713. //exclmode = (_O_BINARY|_O_RDWR|_O_CREAT|_O_EXCL );
  3714. //truncmode = (_O_BINARY|_O_RDWR|_O_TRUNC);
  3715. char *fmode = "w+x";
  3716. #ifdef _WIN32
  3717. if(mode==CDP_CREATE_TEMPORARY){
  3718. exclmode |= /*_O_SHORT_LIVED*/_O_TEMPORARY; //create as temporary, if poss no flush to disk
  3719. }
  3720. #else
  3721. /* TODO: replace with mkstemp, maybe use origname as part of template? */
  3722. /* RWD MAR 2015, need to eliminate call to tmpnam,
  3723. * without having to alloc new memory for modifiable name for mkstemp() */
  3724. /* only the old GUI programs (GrainMill) ask for a temporary filename, anyway... */
  3725. //if(mode==CDP_CREATE_TEMPORARY)
  3726. // name = tmpnam(NULL);
  3727. #endif
  3728. if(mode==CDP_CREATE_RDONLY){
  3729. //exclmode = (_O_BINARY|_O_RDONLY|_O_CREAT|_O_EXCL );
  3730. //truncmode = (_O_BINARY|_O_RDONLY|_O_TRUNC);
  3731. fmode = "r+x";
  3732. }
  3733. if((fp = fopen(name,fmode ))!= NULL)
  3734. return fp;
  3735. if(errno != EEXIST)
  3736. return fp;
  3737. if((ovrflg = getenv("CDP_OVERWRITE_FILE")) == 0)
  3738. return fp;
  3739. if(strcmp(ovrflg, "*") != 0
  3740. &&!comparewithlist(ovrflg, origname))
  3741. return fp;
  3742. // allow overwriting (I hope...) */
  3743. return fopen(name,"w+");
  3744. }
  3745. #endif
  3746. //RWD 2022 removed old sfcreat()
  3747. static int file_exists(const char * fname)
  3748. {
  3749. int rc = 0;
  3750. struct stat buffer;
  3751. rc = stat(fname,&buffer);
  3752. if(rc == 0){
  3753. errno = EEXIST;
  3754. rsferrstr = "Can't create SFile, already exists";
  3755. return 1;
  3756. }
  3757. else
  3758. return 0;
  3759. }
  3760. /********* SFSY98 extension: supply format info for streaming, etc *******/
  3761. //RWD.6.99 supports all new legal formats, except WAVE_EX (use sfcreat_ex)
  3762. //RWD.1.99 added mode arg to create temporary file in Current Directory
  3763. /*RWD 2007: change size params to __int64 */
  3764. int sfcreat_formatted(const char *name, __int64 size, __int64 *outsize,int channels,
  3765. int srate, int stype,cdp_create_mode mode) {
  3766. int i, rc;
  3767. struct sf_file *f;
  3768. char *sfpath;
  3769. /* RWD March 2014 */
  3770. char *ext_default = "wav";
  3771. /*RWD 2007 */
  3772. __int64 freespace = getdrivefreespace(name) - LEAVESPACE;
  3773. if((sfpath = mksfpath(name)) == NULL)
  3774. return -1;
  3775. if((i = allocsffile(sfpath)) < 0)
  3776. return -1;
  3777. f = sf_files[i];
  3778. #ifdef ENABLE_PVX
  3779. /* a split file creation: create partly-complete header, to be filled in later by host.
  3780. * we receive channels (which sets FFTsize for pvx).
  3781. * currently, pvsys create func sets winlen (etc) to default values if arg = 0 : might need to redesign this!
  3782. * horrible suspicion progs ask for pvoc srate = int analysis rate.
  3783. * Not sure how to use the size args.
  3784. * so we will ignore them unless and until this creates a problem!
  3785. */
  3786. // CDP code covers this, but pvocsys doesn't
  3787. if(file_exists(name)){
  3788. #ifdef _DEBUG
  3789. fprintf(stderr,"file exists - can't create\n");
  3790. #endif
  3791. freesffile(i);
  3792. return -1;
  3793. }
  3794. if(gettypefromname98(name) == pvxfile){
  3795. //need to get source (CDP) stype into file header
  3796. int pv_stype = STYPE_16;
  3797. int rc = 0;
  3798. switch(stype) {
  3799. case INT2424:
  3800. case INT2024:
  3801. pv_stype = STYPE_24;
  3802. break;
  3803. case INT2432:
  3804. case INT_32:
  3805. pv_stype = STYPE_32;
  3806. break;
  3807. case FLOAT32:
  3808. pv_stype = STYPE_IEEE_FLOAT;
  3809. break;
  3810. default:
  3811. break;
  3812. }
  3813. f->filetype = pvxfile;
  3814. // setup property block
  3815. # ifdef _DEBUG
  3816. assert(f->pvxprops == NULL);
  3817. assert(f->curpropsize == 0);
  3818. assert(f->props == NULL);
  3819. # endif
  3820. f->proplim = 2000; /* bytes; arbitrary. each putprop call checks this */
  3821. f->pvxprops = calloc(1,sizeof(PVOCDATA));
  3822. // init what we can, rely on file close to complete header via SFPROPS etc
  3823. rc = pvoc_createfile(name,channels - 2,0,1,PVOC_AMP_FREQ,0,pv_stype, PVOC_HANN,0.0,NULL,0);
  3824. if(rc < 0){
  3825. # ifdef _DEBUG
  3826. fprintf(stderr,"sfsys: pvoc_createfile failed: %s\n", pvoc_errorstr());
  3827. # endif
  3828. return -1;
  3829. }
  3830. else {
  3831. # ifdef _DEBUG
  3832. // fprintf(stderr,"pvoc_createfile succeeded i= %d,rc = %d\n",i,rc);
  3833. # endif
  3834. }
  3835. f->pvxfileno = rc;
  3836. if(!pvoc_getpvxprops(f->pvxfileno,f->pvxprops)){
  3837. fprintf(stderr,"sfsys: error from pvoc_getpvxprops\n");
  3838. }
  3839. pvoc_set_needsupdate(f->pvxfileno);
  3840. f->readonly = 0; /* NB: contols if sfputprop() etc succeeds */
  3841. # ifdef _DEBUG
  3842. assert(f->pvxprops->nAnalysisBins > 0);
  3843. # endif
  3844. return i+SFDBASE;
  3845. }
  3846. #endif
  3847. // from here: just normal CDP files
  3848. //RWD: this is OK, as it tells us we cannot CREATE more than one file of the same name, or one already opened
  3849. if(f->refcnt > 1) {
  3850. rsferrno = ESFNOTOPEN;
  3851. rsferrstr = "Can't open file more than once - yet!";
  3852. freesffile(i);
  3853. return -1;
  3854. }
  3855. #if defined _WIN32
  3856. if((f->fileno = doopen(f->filename, name,mode)) == INVALID_HANDLE_VALUE) {
  3857. DWORD w_errno = GetLastError();
  3858. #else
  3859. if((f->fileno = doopen(f->filename, name,mode)) == NULL) {
  3860. #endif
  3861. #if defined _WIN32
  3862. switch(w_errno) {
  3863. case ERROR_INVALID_NAME:
  3864. rsferrno = ESFNOTOPEN;
  3865. rsferrstr = "Can't create SFile, Illegal filename";
  3866. break;
  3867. case ERROR_FILE_EXISTS:
  3868. case ERROR_ALREADY_EXISTS:
  3869. rsferrno = ESFDUPFNAME;
  3870. rsferrstr = "Can't create SFile, already exists";
  3871. break;
  3872. case ERROR_ACCESS_DENIED:
  3873. rsferrno = ESFNOTOPEN;
  3874. rsferrstr = "Can't create SFile, permission denied";
  3875. break;
  3876. default:
  3877. rsferrno = ESFNOTOPEN;
  3878. rsferrstr = "Can't create SFile, Internal error";
  3879. }
  3880. #else
  3881. switch(errno) {
  3882. case EINVAL:
  3883. rsferrno = ESFNOTOPEN;
  3884. rsferrstr = "Can't create SFile, Illegal filename";
  3885. break;
  3886. case EEXIST:
  3887. rsferrno = ESFDUPFNAME;
  3888. rsferrstr = "Can't create SFile, already exists";
  3889. break;
  3890. case EACCES:
  3891. rsferrno = ESFNOTOPEN;
  3892. rsferrstr = "Can't create SFile, permission denied";
  3893. break;
  3894. default:
  3895. rsferrno = ESFNOTOPEN;
  3896. rsferrstr = "Can't create SFile, Internal error";
  3897. }
  3898. #endif
  3899. freesffile(i);
  3900. return -1;
  3901. }
  3902. if(size < 0)
  3903. f->sizerequested = freespace;
  3904. else if(size >= freespace) {
  3905. rsferrno = ESFNOSPACE;
  3906. rsferrstr = "Not enough space on Disk to create sound file";
  3907. //RWD.7.99
  3908. #if defined _WIN32
  3909. CloseHandle(f->fileno);
  3910. DeleteFile(f->filename);
  3911. #else
  3912. fclose(f->fileno);
  3913. remove(f->filename);
  3914. #endif
  3915. freesffile(i);
  3916. return -1;
  3917. } else
  3918. f->sizerequested = /*size&~1*/ size; /* RWD NOV 2001 NO ROUNDING! We have 24bit samples now! */
  3919. f->readonly = 0;
  3920. f->header_set = 0;
  3921. ///RWD.6.5.99 prepare peak storage
  3922. f->peaks = (CHPEAK *) calloc(channels, sizeof(CHPEAK));
  3923. if(f->peaks==NULL){
  3924. rsferrno = ESFNOMEM;
  3925. rsferrstr = "No memory to create peak data storage";
  3926. //RWD.7.99
  3927. #if defined _WIN32
  3928. CloseHandle(f->fileno);
  3929. DeleteFile(f->filename);
  3930. #else
  3931. fclose(f->fileno);
  3932. remove(f->filename);
  3933. #endif
  3934. freesffile(i);
  3935. return -1;
  3936. }
  3937. switch(f->filetype = gettypefromname98(f->filename)) {
  3938. char *ext;
  3939. /******* RWD.7.98 all we have to do to write a requested format is to fill in the data in f->fmtchunk
  3940. ******* and get wrwavhdr() to read this in! *****/
  3941. case riffwav:
  3942. rc = wrwavhdr98(f,channels,srate,stype);
  3943. break;
  3944. case eaaiff:
  3945. //make sure AIFF format is legal!
  3946. if(stype==SAMP_2432){
  3947. //reject here, as can't tell caller
  3948. rsferrno = ESFBADPARAM;
  3949. rsferrstr = "requested sample type illegal for AIFF files";
  3950. return -1;
  3951. }
  3952. if(stype==SAMP_FLOAT){
  3953. //we now require AIFC for float formats
  3954. f->filetype = aiffc;
  3955. rc = wraifchdr(f,channels,srate,stype);
  3956. }
  3957. else
  3958. rc = wraiffhdr98(f,channels,srate,stype);
  3959. break;
  3960. //RWD temporary
  3961. case aiffc:
  3962. //make sure AIFF format is legal!
  3963. if(stype==SAMP_2432){
  3964. //reject here, as can't tell caller
  3965. rsferrno = ESFBADPARAM;
  3966. rsferrstr = "requested sample type illegal for AIFF files";
  3967. return -1;
  3968. }
  3969. rc = wraifchdr(f,channels,srate,stype);
  3970. break;
  3971. case cdpfile:
  3972. /* RWD MAR 2015 as above */
  3973. if((ext = getenv("CDP_SOUND_EXT")) == NULL || strlen(ext) == 0) {
  3974. ext = ext_default;
  3975. }
  3976. f->min_header = SFILE_ANAL; /*RWD Nov 2009: but we don't want PEAK, CUE for analysis files! */
  3977. if(f->peaks){
  3978. free(f->peaks);
  3979. f->peaks = NULL;
  3980. }
  3981. if(_stricmp(ext, "wav") == 0){
  3982. rc = wrwavhdr98(f,channels,srate,stype); /*RWD 5:2003*/
  3983. f->filetype = riffwav;
  3984. }
  3985. else if(_stricmp(ext, "aif") == 0 || _stricmp(ext, "aiff") == 0){
  3986. if(stype==SAMP_FLOAT){
  3987. //we now require AIFC for float formats
  3988. f->filetype = aiffc;
  3989. rc = wraifchdr(f,channels,srate,stype);
  3990. }
  3991. else{
  3992. rc=wraiffhdr98(f,channels,srate,stype);
  3993. f->filetype= eaaiff;
  3994. }
  3995. }
  3996. //RWD.1.99 temporary
  3997. else if(_stricmp(ext, "aic") == 0
  3998. || _stricmp(ext, "afc") == 0
  3999. || _stricmp(ext, "aifc") == 0){
  4000. rc=wraifchdr(f,channels,srate,stype);
  4001. f->filetype= aiffc;
  4002. }
  4003. else {
  4004. rsferrno = ESFBADPARAM;
  4005. rsferrstr = "unknown sound file type - bad CDP_SOUND_EXT setting";
  4006. //RWD.7.99
  4007. #if defined _WIN32
  4008. CloseHandle(f->fileno);
  4009. DeleteFile(f->filename);
  4010. #else
  4011. fclose(f->fileno);
  4012. remove(f->filename);
  4013. #endif
  4014. return -1;
  4015. }
  4016. break;
  4017. default:
  4018. rsferrno = ESFNOSTYPE;
  4019. rsferrstr = "Internal error: can't find filetype";
  4020. rc = 1;
  4021. }
  4022. if(rc) {
  4023. //RWD.7.99
  4024. #if defined _WIN32
  4025. CloseHandle(f->fileno);
  4026. DeleteFile(f->filename);
  4027. #else
  4028. fclose(f->fileno);
  4029. remove(f->filename);
  4030. #endif
  4031. freesffile(i);
  4032. return -1;
  4033. }
  4034. f->datachunksize = 0;
  4035. f->infochanged = 0;
  4036. f->todelete = 0;
  4037. if(outsize != 0)
  4038. *outsize = (unsigned int) f->sizerequested;
  4039. f->curpos = 0;
  4040. return i+SFDBASE;
  4041. }
  4042. //special version for wave-ex
  4043. //props is both in and out
  4044. int sfcreat_ex(const char *name, __int64 size, __int64 *outsize,SFPROPS *props,int min_header,cdp_create_mode mode)
  4045. {
  4046. int i, rc;
  4047. int stype = -1;
  4048. struct sf_file *f;
  4049. char *sfpath;
  4050. char *ext_default = "wav"; /* RWD March 2014 */
  4051. unsigned long freespace = getdrivefreespace(name) - LEAVESPACE;
  4052. if((sfpath = mksfpath(name)) == NULL)
  4053. return -1;
  4054. if(min_header < SFILE_MINIMUM || min_header > SFILE_CDP){
  4055. rsferrno = ESFBADPARAM;
  4056. rsferrstr = "bad min_header spec";
  4057. return -1;
  4058. }
  4059. if((i = allocsffile(sfpath)) < 0)
  4060. return -1;
  4061. f = sf_files[i];
  4062. //RWD: this is OK, as it tells us we cannot CREATE more than one file of the same name, or one already opened
  4063. if(f->refcnt > 1) {
  4064. rsferrno = ESFNOTOPEN;
  4065. rsferrstr = "Can't open file more than once - yet!";
  4066. freesffile(i);
  4067. return -1;
  4068. }
  4069. //can only minimise header for wavefile!
  4070. if(props->type == wt_wave)
  4071. f->min_header = min_header;
  4072. //reject analysis formats if not floatsams
  4073. else{ // must be wt_analysis
  4074. if(props->samptype != FLOAT32){
  4075. rsferrno = ESFBADPARAM;
  4076. rsferrstr = "Analysis data must be floats";
  4077. freesffile(i);
  4078. return -1;
  4079. }
  4080. }
  4081. switch(props->samptype){
  4082. case (SHORT16):
  4083. stype = SAMP_SHORT;
  4084. break;
  4085. case(FLOAT32):
  4086. stype = SAMP_FLOAT;
  4087. break;
  4088. case(INT_32):
  4089. stype = SAMP_LONG;
  4090. break;
  4091. case(INT2424):
  4092. stype = SAMP_2424;
  4093. break;
  4094. case(INT2024):
  4095. stype = SAMP_2024;
  4096. break;
  4097. case(INT2432):
  4098. stype = SAMP_2432;
  4099. break;
  4100. default:
  4101. rsferrno = ESFBADPARAM;
  4102. rsferrstr = "unsupported sample type"; //add speaker mask stuff ere long, if WAVE_EX
  4103. freesffile(i);
  4104. return -1;
  4105. break;
  4106. }
  4107. #if defined _WIN32
  4108. if((f->fileno = doopen(f->filename, name,mode)) == INVALID_HANDLE_VALUE) {
  4109. DWORD w_errno = GetLastError();
  4110. #else
  4111. if((f->fileno = doopen(f->filename, name,mode)) == NULL) {
  4112. #endif
  4113. #if defined _WIN32
  4114. switch(w_errno) {
  4115. case ERROR_INVALID_NAME:
  4116. rsferrno = ESFNOTOPEN;
  4117. rsferrstr = "Can't create SFile, Illegal filename";
  4118. break;
  4119. case ERROR_FILE_EXISTS:
  4120. case ERROR_ALREADY_EXISTS:
  4121. rsferrno = ESFDUPFNAME;
  4122. rsferrstr = "Can't create SFile, already exists";
  4123. break;
  4124. case ERROR_ACCESS_DENIED:
  4125. rsferrno = ESFNOTOPEN;
  4126. rsferrstr = "Can't create SFile, permission denied";
  4127. break;
  4128. default:
  4129. rsferrno = ESFNOTOPEN;
  4130. rsferrstr = "Can't create SFile, Internal error";
  4131. }
  4132. #else
  4133. switch(errno) {
  4134. case EINVAL:
  4135. rsferrno = ESFNOTOPEN;
  4136. rsferrstr = "Can't create SFile, Illegal filename";
  4137. break;
  4138. case EEXIST:
  4139. rsferrno = ESFDUPFNAME;
  4140. rsferrstr = "Can't create SFile, already exists";
  4141. break;
  4142. case EACCES:
  4143. rsferrno = ESFNOTOPEN;
  4144. rsferrstr = "Can't create SFile, permission denied";
  4145. break;
  4146. default:
  4147. rsferrno = ESFNOTOPEN;
  4148. rsferrstr = "Can't create SFile, Internal error";
  4149. }
  4150. #endif
  4151. freesffile(i);
  4152. return -1;
  4153. }
  4154. if(size < 0)
  4155. f->sizerequested = freespace;
  4156. else if(size >= freespace) {
  4157. rsferrno = ESFNOSPACE;
  4158. rsferrstr = "Not enough space on Disk to create sound file";
  4159. #if defined _WIN32
  4160. CloseHandle(f->fileno);
  4161. DeleteFile(f->filename);
  4162. #else
  4163. fclose(f->fileno);
  4164. remove(f->filename);
  4165. #endif
  4166. freesffile(i);
  4167. return -1;
  4168. } else
  4169. f->sizerequested = (size/* + 1*/)/* &~1*/; /*RWD use size+1) to get 16bit pad for 24bit files */
  4170. f->readonly = 0;
  4171. f->header_set = 0;
  4172. ///RWD.6.5.99 prepare peak storage: wave and binary envelope are OK
  4173. if(props->type == wt_wave || props->type== wt_binenv){
  4174. f->peaks = (CHPEAK *) calloc(props->chans, sizeof(CHPEAK));
  4175. if(f->peaks==NULL){
  4176. rsferrno = ESFNOMEM;
  4177. rsferrstr = "No memory to create peak data storage";
  4178. #if defined _WIN32
  4179. CloseHandle(f->fileno);
  4180. DeleteFile(f->filename);
  4181. #else
  4182. fclose(f->fileno);
  4183. remove(f->filename);
  4184. #endif
  4185. freesffile(i);
  4186. return -1;
  4187. }
  4188. }
  4189. switch(f->filetype = gettypefromname98(f->filename)) {
  4190. char *ext;
  4191. /******* RWD.7.98 all we have to do to write a requested format is to fill in the data in f->fmtchunk
  4192. ******* and get wrwavhdr() to read this in! *****/
  4193. case riffwav:
  4194. if(props->chformat >= MC_STD){
  4195. f->filetype = wave_ex;
  4196. props->format = WAVE_EX;
  4197. rc = wrwavex(f, props);
  4198. }
  4199. else {
  4200. props->chformat = STDWAVE;
  4201. props->format = WAVE;
  4202. rc = wrwavhdr98(f,props->chans,props->srate,stype);
  4203. }
  4204. break;
  4205. //TODO: get the aiff extended formats sorted!
  4206. case eaaiff:
  4207. //for now, we have to IGNORE chformat requests
  4208. props->chformat = STDWAVE;
  4209. props->format = AIFF;
  4210. //make sure AIFF format is legal!
  4211. if(stype==SAMP_2432){
  4212. stype = SAMP_2424;
  4213. props->samptype = INT2424;
  4214. }
  4215. if(stype==SAMP_FLOAT){
  4216. //we now require AIFC for float formats
  4217. props->format = AIFC;
  4218. f->filetype = aiffc;
  4219. rc = wraifchdr(f,props->chans,props->srate,stype);
  4220. }
  4221. else
  4222. rc = wraiffhdr98(f,props->chans,props->srate,stype);
  4223. break;
  4224. case aiffc:
  4225. props->format = AIFC;
  4226. //make sure AIFF format is legal!
  4227. if(stype==SAMP_2432){
  4228. stype = SAMP_2424;
  4229. props->samptype = INT2424;
  4230. }
  4231. rc = wraifchdr(f,props->chans,props->srate,stype);
  4232. break;
  4233. case cdpfile:
  4234. /* RWD MAR 2015 as above */
  4235. if((ext = getenv("CDP_SOUND_EXT")) == NULL || strlen(ext) == 0) {
  4236. ext = ext_default;
  4237. }
  4238. if(_stricmp(ext, "wav") == 0){
  4239. if(props->chformat > MC_STD){
  4240. f->filetype = wave_ex;
  4241. props->format = WAVE_EX;
  4242. rc = wrwavex(f, props);
  4243. }
  4244. else {
  4245. props->chformat = STDWAVE;
  4246. props->format = WAVE;
  4247. rc = wrwavhdr98(f,props->chans,props->srate,stype);
  4248. f->filetype = riffwav;
  4249. }
  4250. }
  4251. else if(_stricmp(ext, "aif") == 0 || _stricmp(ext, "aiff") == 0){
  4252. props->chformat = STDWAVE;
  4253. props->format = AIFF;
  4254. if(stype==SAMP_FLOAT){
  4255. //we now require AIFC for float formats
  4256. props->format = AIFC;
  4257. f->filetype = aiffc;
  4258. rc = wraifchdr(f,props->chans,props->srate,stype);
  4259. }
  4260. else {
  4261. rc = wraiffhdr98(f,props->chans,props->srate,stype);
  4262. f->filetype= eaaiff;
  4263. }
  4264. }
  4265. //RWD.1.99 temporary
  4266. else if(_stricmp(ext, "aic") == 0
  4267. || _stricmp(ext, "afc") == 0
  4268. || _stricmp(ext, "aifc") == 0){
  4269. props->format = AIFC;
  4270. f->filetype = aiffc;
  4271. rc = wraifchdr(f,props->chans,props->srate,stype);
  4272. }
  4273. else {
  4274. rsferrno = ESFBADPARAM;
  4275. rsferrstr = "unknown sound file type - bad CDP_SOUND_EXT setting";
  4276. //RWD.7.99
  4277. #if defined _WIN32
  4278. CloseHandle(f->fileno);
  4279. DeleteFile(f->filename);
  4280. #else
  4281. fclose(f->fileno);
  4282. remove(f->filename);
  4283. #endif
  4284. return -1;
  4285. }
  4286. break;
  4287. default:
  4288. rsferrno = ESFNOSTYPE;
  4289. rsferrstr = "Internal error: can't find filetype";
  4290. rc = 1;
  4291. }
  4292. if(rc) {
  4293. //RWD.7.99
  4294. #if defined _WIN32
  4295. CloseHandle(f->fileno);
  4296. DeleteFile(f->filename);
  4297. #else
  4298. fclose(f->fileno);
  4299. remove(f->filename);
  4300. #endif
  4301. freesffile(i);
  4302. return -1;
  4303. }
  4304. f->datachunksize = 0;
  4305. f->infochanged = 0;
  4306. f->todelete = 0;
  4307. if(outsize != 0)
  4308. *outsize = f->sizerequested;
  4309. f->curpos = 0;
  4310. if(props->type==wt_analysis){
  4311. /*Write all pvoc properties*/
  4312. if(addprop(f,"original sampsize",(char *)&(props->origsize), sizeof(/*long*/int))<0){
  4313. rsferrstr = "Failure to write original sample size";
  4314. return -1;
  4315. }
  4316. if(addprop(f,"original sample rate",(char *)&(props->origrate),sizeof(/*long*/int))<0){
  4317. rsferrstr = "Failure to write original sample rate";
  4318. }
  4319. if(addprop(f,"arate",(char *)&(props->arate),sizeof(float)) < 0){
  4320. rsferrstr = "Failure to write analysis sample rate";
  4321. }
  4322. if(addprop(f,"analwinlen",(char *)&(props->winlen),sizeof(int)) < 0){
  4323. rsferrstr = "Failure to write analysis window length";
  4324. }
  4325. if(addprop(f,"decfactor",(char *)&(props->decfac),sizeof(int)) < 0){
  4326. rsferrstr = "Failure to write decimation factor";
  4327. }
  4328. }
  4329. return i+SFDBASE;
  4330. }
  4331. //RWD.1.99 new func to enable current sfile (e.g temporary) to be reopened for writing
  4332. //return 1 for success, 0 for error
  4333. //new channel/sample formats are accepted, but the cdp_create_mode cannot be changed, nor the file format
  4334. //(without alot mre jiggery-pokery...)
  4335. //BIG QUESTION: ALLOW THIS ONLY FOR TEMPORARY FILES?
  4336. //note we do not call freesfile[] here, as the file is owned externally
  4337. //current dependency: GRAINMILL
  4338. //will need sndrecreat_formatted eventually, NB set buffer size for 24bit formats!
  4339. int
  4340. sfrecreat_formatted(int sfd, __int64 size, __int64 *outsize,int channels,
  4341. int srate, int stype)
  4342. {
  4343. int rc;
  4344. struct sf_file *f;
  4345. char *ext_default = "wav";
  4346. __int64 freespace;
  4347. //might as well validate the params
  4348. if(channels < 1 || srate <= 0)
  4349. return 0;
  4350. //ho hum, need stype as a typedef...
  4351. // we're not interested in 8-bit stuff!
  4352. if((stype >= SAMP_MASKED) || stype == SAMP_BYTE)
  4353. return 0;
  4354. if((f = findfile(sfd)) == 0)
  4355. return 0;
  4356. //RWD: this is OK, as it tells us we cannot CREATE more than one file of the same name, or one already opened
  4357. if(f->refcnt > 1) {
  4358. rsferrno = ESFNOTOPEN;
  4359. rsferrstr = "Can't (re)create file more than once!";
  4360. return 0;
  4361. }
  4362. if(f->readonly == 1)
  4363. return 0;
  4364. #if defined _WIN32
  4365. if(w_ch_size(f->fileno, 0L) < 0) {
  4366. #else
  4367. if(ftruncate(fileno(f->fileno), 0) < 0) {
  4368. #endif
  4369. rsferrno = ESFWRERR;
  4370. rsferrstr = "write error resetting file";
  4371. return 0;
  4372. }
  4373. freespace = getdrivefreespace(f->filename) - LEAVESPACE;
  4374. if(size < 0)
  4375. f->sizerequested = freespace;
  4376. else if((unsigned long)size >= freespace) {
  4377. rsferrno = ESFNOSPACE;
  4378. rsferrstr = "Not enough space on Disk to create sound file";
  4379. return 0;
  4380. } else
  4381. f->sizerequested = /*size&~1*/ size; /*RWD Nov 2001: accept 24bit samples */
  4382. f->readonly = 0;
  4383. f->header_set = 0;
  4384. //RWD.6.5.99 : accept PEAKS for now, but may need to forbid unless wave or binenv, as above
  4385. if(f->peaks){
  4386. free(f->peaks);
  4387. f->peaks = (CHPEAK *) calloc(channels,sizeof(CHPEAK));
  4388. if(f->peaks==NULL){
  4389. rsferrno = ESFNOMEM;
  4390. rsferrstr = "No memory for peak data";
  4391. return 0;
  4392. }
  4393. }
  4394. //we don't change f->min_header...
  4395. switch(f->filetype) {
  4396. char *ext;
  4397. case riffwav:
  4398. rc = wrwavhdr98(f,channels,srate,stype);
  4399. break;
  4400. case eaaiff:
  4401. //make sure AIFF format is legal!
  4402. if(stype==SAMP_2432){
  4403. //reject here, as can't tell caller
  4404. rsferrno = ESFBADPARAM;
  4405. rsferrstr = "requested sample type illegal for AIFF files";
  4406. return -1;
  4407. }
  4408. if(stype==SAMP_FLOAT){
  4409. //we now require AIFC for float formats
  4410. f->filetype = aiffc;
  4411. rc = wraifchdr(f,channels,srate,stype);
  4412. }
  4413. else
  4414. rc = wraiffhdr98(f,channels,srate,stype);
  4415. break;
  4416. case aiffc:
  4417. //make sure AIFF format is legal!
  4418. if(stype==SAMP_2432){
  4419. //reject here, as can't tell caller
  4420. rsferrno = ESFBADPARAM;
  4421. rsferrstr = "requested sample type illegal for AIFF files";
  4422. return -1;
  4423. }
  4424. rc = wraifchdr(f,channels,srate,stype);
  4425. break;
  4426. case cdpfile:
  4427. /* RWD MAR 2015 as above */
  4428. if((ext = getenv("CDP_SOUND_EXT")) == NULL || strlen(ext) == 0) {
  4429. // rsferrno = ESFBADPARAM;
  4430. // rsferrstr = "unknown sound file type - extension not set";
  4431. // rc = 1;
  4432. ext = ext_default;
  4433. }
  4434. if(_stricmp(ext, "wav") == 0){
  4435. rc = wrwavhdr98(f,channels,srate,stype);
  4436. f->filetype = riffwav;
  4437. }
  4438. else if(_stricmp(ext, "aif") == 0 || _stricmp(ext, "aiff") == 0){
  4439. if(stype==SAMP_FLOAT){
  4440. //we now require AIFC for float formats
  4441. f->filetype = aiffc;
  4442. rc = wraifchdr(f,channels,srate,stype);
  4443. }
  4444. else {
  4445. rc = wraiffhdr98(f,channels,srate,stype);
  4446. f->filetype= eaaiff;
  4447. }
  4448. }
  4449. //RWD.1.99 temporary
  4450. else if(_stricmp(ext, "aic") == 0
  4451. || _stricmp(ext, "afc") == 0
  4452. || _stricmp(ext, "aifc") == 0){
  4453. f->filetype = aiffc;
  4454. rc = wraifchdr(f,channels,srate,stype);
  4455. }
  4456. else {
  4457. rsferrno = ESFBADPARAM;
  4458. rsferrstr = "unknown sound file type - bad CDP_SOUND_EXT setting";
  4459. rc = 1;
  4460. }
  4461. break;
  4462. default:
  4463. rsferrno = ESFNOSTYPE;
  4464. rsferrstr = "Internal error: can't find filetype";
  4465. rc = 1;
  4466. }
  4467. if(rc) {
  4468. return 0;
  4469. }
  4470. f->datachunksize = 0;
  4471. f->infochanged = 0;
  4472. f->todelete = 0;
  4473. if(outsize != 0)
  4474. *outsize = f->sizerequested;
  4475. f->curpos = 0;
  4476. return 1;
  4477. }
  4478. //RWD OCT97
  4479. int
  4480. sfgetwordsize(int sfd)
  4481. {
  4482. struct sf_file *f;
  4483. if((f = findfile(sfd)) == 0)
  4484. return -1;
  4485. return f->fmtchunkEx.Format.wBitsPerSample;
  4486. }
  4487. __int64 sfgetdatasize(int sfd)
  4488. {
  4489. struct sf_file *f;
  4490. if((f = findfile(sfd)) == 0)
  4491. return -1;
  4492. return f->datachunksize;
  4493. }
  4494. #if defined _WIN32
  4495. int sf_is_shortcut(int sfd,char *name)
  4496. {
  4497. struct sf_file *f;
  4498. if((f = findfile(sfd)) == 0)
  4499. return -1;
  4500. if(f->is_shortcut){
  4501. if(name != NULL)
  4502. strcpy(name,f->filename);
  4503. }
  4504. return f->is_shortcut;
  4505. }
  4506. #endif
  4507. /*RWD: nb cnt arg is seen as count of BYTES to fill (expecting cnt/sizeof(sample) words);
  4508. f->curpos expected to contain bytes of SHORTS or FLOATS
  4509. */
  4510. int
  4511. sfread(int sfd, char *buf, int cnt)
  4512. {
  4513. struct sf_file *f;
  4514. short *sp;
  4515. DWORD *dp;
  4516. __int64 remain;
  4517. int i;
  4518. //int got = 0;
  4519. if((f = findfile(sfd)) == 0)
  4520. return -1;
  4521. cnt = cnt & ~(SECSIZE-1);
  4522. /*RWD OCT97: here, remain IS size-specific, so curpos must be, too*/
  4523. if((remain = (int)(f->datachunksize - f->curpos)) < 0)
  4524. remain = 0;
  4525. if(cnt > remain)
  4526. cnt = remain;
  4527. if(cnt == 0)
  4528. return 0;
  4529. if(f->fmtchunkEx.Format.wBitsPerSample == 8)
  4530. cnt /= 2; /*see below...*/
  4531. if(doread(f, buf, cnt)) { /*bytes, bytecnt*/
  4532. rsferrno = ESFRDERR;
  4533. rsferrstr = "Read error";
  4534. return -1;
  4535. }
  4536. switch(f->fmtchunkEx.Format.wBitsPerSample) {
  4537. case 8:
  4538. if(f->filetype == riffwav || f->filetype ==wave_ex) {
  4539. for(i = cnt-1; i >= 0; i--)
  4540. ((short *)buf)[i] = (buf[i]-128)<<8;
  4541. } else if((f->filetype == eaaiff) || (f->filetype==aiffc)) { //RWD.1.99
  4542. for(i = cnt-1; i >= 0; i--)
  4543. ((short *)buf)[i] = ((signed char *)buf)[i];
  4544. } else
  4545. abort(); //RWD ouch!
  4546. cnt *= 2; // restored from above
  4547. break;
  4548. case 16:
  4549. if(REVDATAINFILE(f)) {
  4550. sp = (short *)buf;
  4551. for(i = cnt/sizeof(short); i > 0; i--) {
  4552. *sp = REVWBYTES(*sp);
  4553. sp++;
  4554. }
  4555. }
  4556. break;
  4557. case 32:
  4558. if(REVDATAINFILE(f)) {
  4559. dp = (DWORD *)buf;
  4560. for(i = cnt/sizeof(DWORD); i > 0; i--) {
  4561. *dp = REVDWBYTES(*dp);
  4562. dp++;
  4563. }
  4564. }
  4565. break;
  4566. default:
  4567. // abort(); // ouch again!
  4568. //RW.6.99
  4569. rsferrno = ESFBADPARAM;
  4570. rsferrstr = "cannot read unsupported sample type";
  4571. return -1;
  4572. }
  4573. f->curpos += cnt; //assumes pos in SHORTS or FLOATS buffer
  4574. return cnt;
  4575. }
  4576. //RWD: the original func - no support for new formats, but must eliminate abort() call!
  4577. /* RWD 2007 NB : these funcs all return -1 for error, so are forced to handle only signed longs */
  4578. /* therefore: NOT ready for 4GB files ! */
  4579. int
  4580. sfwrite(int sfd, char *outbuf, int cnt)
  4581. {
  4582. struct sf_file *f;
  4583. int i;
  4584. __int64 remain;
  4585. short *ssp, *sdp;
  4586. DWORD *dsp, *ddp;
  4587. char *buf = outbuf;
  4588. if((f = findfile(sfd)) == 0)
  4589. return -1;
  4590. if(f->readonly) {
  4591. rsferrno = ESFREADONLY;
  4592. rsferrstr = "Can't write to read only file";
  4593. return -1;
  4594. }
  4595. if(f->fmtchunkEx.Format.wBitsPerSample == 8) {
  4596. rsferrno = ESFREADONLY;
  4597. rsferrstr = "Can't write to 8bits/sample files";
  4598. return -1;
  4599. }
  4600. cnt = cnt & ~(SECSIZE-1);
  4601. if(f->sizerequested >= 0) { /* creating file - explicit size */
  4602. if((remain = f->sizerequested - f->curpos) < 0)
  4603. remain = 0;
  4604. if(cnt > (int) remain)
  4605. cnt = (int) remain;
  4606. } else if(f->sizerequested == ES_EXIST) { /* existing file - can't change size */
  4607. if((remain = f->datachunksize - f->curpos) < 0)
  4608. remain = 0;
  4609. if(cnt > (int) remain)
  4610. cnt = (int) remain;
  4611. }
  4612. if(cnt == 0)
  4613. return 0;
  4614. if(REVDATAINFILE(f)) {
  4615. if((buf = (char *) malloc(cnt)) == 0) {
  4616. rsferrno = ESFWRERR;
  4617. rsferrstr = "Write error: can't allocate byte swap buffer";
  4618. return -1;
  4619. }
  4620. switch(f->fmtchunkEx.Format.wBitsPerSample) {
  4621. case 16:
  4622. ssp = (short *)outbuf;
  4623. sdp = (short *)buf;
  4624. for(i = cnt/sizeof(short); i > 0; i--) {
  4625. *sdp = REVWBYTES(*ssp);
  4626. ssp++;
  4627. sdp++;
  4628. }
  4629. break;
  4630. case 32:
  4631. dsp = (DWORD *)outbuf;
  4632. ddp = (DWORD *)buf;
  4633. for(i = cnt/sizeof(DWORD); i > 0; i--) {
  4634. *ddp = REVDWBYTES(*dsp);
  4635. dsp++;
  4636. ddp++;
  4637. }
  4638. break;
  4639. default:
  4640. #ifdef NOTDEF
  4641. abort();
  4642. #endif
  4643. rsferrno = ESFBADPARAM;
  4644. rsferrstr = "cannot write unsupported sample format";
  4645. return -1;
  4646. }
  4647. }
  4648. /* else creating file - max size */
  4649. if(dowrite(f, buf, cnt)) {
  4650. rsferrno = ESFWRERR;
  4651. rsferrstr = "Write error";
  4652. if(buf != outbuf)
  4653. free(buf);
  4654. return -1;
  4655. }
  4656. f->curpos += cnt;
  4657. if(f->curpos > f->datachunksize) {
  4658. f->datachunksize = f->curpos;
  4659. f->infochanged = 1;
  4660. }
  4661. if(buf != outbuf)
  4662. free(buf);
  4663. return cnt;
  4664. }
  4665. /* RWD: OBSOLETE - NOT IN USE NOW! */
  4666. int
  4667. sfseek(int sfd, int dist, int whence)
  4668. {
  4669. struct sf_file *f;
  4670. unsigned int newpos = 0u;
  4671. unsigned int size;
  4672. fpos_t bytepos;
  4673. if((f = findfile(sfd)) == 0)
  4674. return -1;
  4675. /*RWD 2007 added casts to silence compiler! */
  4676. size = (unsigned int) sfsize(sfd); /* NB Can't fail! */ //RWD OCT97: NB: assumes file of SHORTS or FLOATS
  4677. switch(whence) {
  4678. case 0:
  4679. newpos = dist;
  4680. break;
  4681. case 1:
  4682. newpos = f->curpos + dist;
  4683. break;
  4684. case 2:
  4685. newpos = size + dist;
  4686. break;
  4687. default:
  4688. rsferrno = ESFBADPARAM;
  4689. rsferrstr = "illegal whence value in sfseek";
  4690. break;
  4691. }
  4692. /* RWD MAR 2015 just to eliminate compiler warning */
  4693. //if(newpos < 0)
  4694. // newpos = 0;
  4695. if(newpos > size)
  4696. newpos = size;
  4697. newpos &= ~(SECSIZE-1);
  4698. f->curpos = newpos; //still size-specific here...
  4699. //RWD OCT97 must seek correctly in 8bit files
  4700. if(f->fmtchunkEx.Format.wBitsPerSample==8)
  4701. newpos /= 2;
  4702. #if defined _WIN32
  4703. newpos += f->datachunkoffset;
  4704. if(SetFilePointer(f->fileno, newpos,NULL, FILE_BEGIN) != newpos) {
  4705. #else
  4706. POS64(bytepos) = newpos + POS64(f->datachunkoffset);
  4707. if(fsetpos(f->fileno, &bytepos) ) {
  4708. #endif
  4709. rsferrno = ESFRDERR; //RWD CDP97
  4710. rsferrstr = "Seek error";
  4711. return -1;
  4712. }
  4713. return f->curpos;
  4714. }
  4715. static char * REV3BYTES(char *samp_24){
  4716. //trick here: just exchange the outer bytes!
  4717. char temp = samp_24[0];
  4718. *samp_24 = samp_24[2];
  4719. samp_24[2] = temp;
  4720. return samp_24;
  4721. }
  4722. /* special buffered sf_routines for new sample sizes */
  4723. int
  4724. sfread_buffered(int sfd, char *buf, int lcnt)
  4725. {
  4726. struct sf_file *f;
  4727. short *sp;
  4728. DWORD *dp;
  4729. #ifdef FILE64_WIN
  4730. __int64 remain,i;
  4731. __int64 cnt = lcnt; /*RWD 2007: lcnt used some places below */
  4732. long containersize;
  4733. #else
  4734. __int64 remain;
  4735. __int64 cnt = lcnt;
  4736. int i,containersize;
  4737. #endif
  4738. //int got = 0;
  4739. if((f = findfile(sfd)) == 0)
  4740. return -1;
  4741. //RWD OCT97: here, remain IS size-specific, so curpos must be, too
  4742. if((remain = (__int64) (f->datachunksize - f->curpos)) < 0)
  4743. remain = 0;
  4744. #ifdef FILE64_WIN
  4745. if((__int64) cnt > remain)
  4746. cnt = (unsigned int) remain;
  4747. #else
  4748. if(cnt > remain)
  4749. cnt = remain;
  4750. #endif
  4751. if(cnt == 0)
  4752. return 0;
  4753. if(f->fmtchunkEx.Format.wBitsPerSample == 8)
  4754. cnt /= 2; //see below...
  4755. if(doread(f, buf, (int) cnt)) { //bytes, bytecnt
  4756. rsferrno = ESFRDERR;
  4757. rsferrstr = "Read error";
  4758. return -1;
  4759. }
  4760. containersize = 8 * (f->fmtchunkEx.Format.nBlockAlign / f->fmtchunkEx.Format.nChannels);
  4761. switch(containersize) {
  4762. case 8:
  4763. if(f->filetype == riffwav || f->filetype ==wave_ex) {
  4764. for(i = cnt-1; i >= 0; i--)
  4765. ((short *)buf)[i] = (buf[i]-128)<<8;
  4766. } else if((f->filetype == eaaiff) || (f->filetype==aiffc)) { //RWD.1.99
  4767. for(i = cnt-1; i >= 0; i--)
  4768. ((short *)buf)[i] = ((signed char *)buf)[i];
  4769. } else
  4770. abort(); //RWD ouch!
  4771. cnt *= 2; // restored from above
  4772. break;
  4773. case 16:
  4774. if(REVDATAINFILE(f)) {
  4775. sp = (short *)buf;
  4776. for(i = cnt/sizeof(short); i > 0; i--) {
  4777. *sp = REVWBYTES(*sp);
  4778. sp++;
  4779. }
  4780. }
  4781. break;
  4782. case(24):
  4783. if(REVDATAINFILE(f)) {
  4784. char *p_byte = buf;
  4785. for(i = cnt/3; i > 0; i--) {
  4786. p_byte = REV3BYTES(p_byte);
  4787. p_byte += 3;
  4788. }
  4789. }
  4790. break;
  4791. case 32:
  4792. if(REVDATAINFILE(f)) {
  4793. dp = (DWORD *)buf;
  4794. for(i = cnt/sizeof(DWORD); i > 0; i--) {
  4795. *dp = REVDWBYTES(*dp);
  4796. dp++;
  4797. }
  4798. }
  4799. break;
  4800. default:
  4801. #ifdef NOTDEF
  4802. abort(); // ouch again!
  4803. #endif
  4804. rsferrno = ESFBADPARAM;
  4805. rsferrstr = "unsupported sample format";
  4806. return -1;
  4807. }
  4808. f->curpos += (DWORD) cnt; //assumes pos in SHORTS or FLOATS buffer
  4809. return (int) cnt;
  4810. }
  4811. //RWD.7.99 TODO: use blockalign to decide what size word to write
  4812. int
  4813. sfwrite_buffered(int sfd, char *outbuf, int lcnt)
  4814. {
  4815. struct sf_file *f;
  4816. __int64 remain;
  4817. __int64 cnt = lcnt;
  4818. short *ssp, *sdp;
  4819. DWORD *dsp, *ddp;
  4820. char *buf = outbuf;
  4821. int containersize;
  4822. if((f = findfile(sfd)) == 0)
  4823. return -1;
  4824. if(f->readonly) {
  4825. rsferrno = ESFREADONLY;
  4826. rsferrstr = "Can't write to read only file";
  4827. return -1;
  4828. }
  4829. if(f->fmtchunkEx.Format.wBitsPerSample == 8) {
  4830. rsferrno = ESFREADONLY;
  4831. rsferrstr = "Can't write to 8bits/sample files";
  4832. return -1;
  4833. }
  4834. //cnt = cnt & ~(SECSIZE-1);
  4835. if(f->sizerequested >= 0) { /* creating file - explicit size */
  4836. if((remain = f->sizerequested - f->curpos) < 0)
  4837. remain = 0;
  4838. if(cnt > remain)
  4839. cnt = remain;
  4840. } else if(f->sizerequested == ES_EXIST) { /* existing file - can't change size */
  4841. if((remain = f->datachunksize - f->curpos) < 0)
  4842. remain = 0;
  4843. if(cnt > remain)
  4844. cnt = remain;
  4845. }
  4846. if(cnt == 0)
  4847. return 0;
  4848. containersize = 8 * (f->fmtchunkEx.Format.nBlockAlign / f->fmtchunkEx.Format.nChannels);
  4849. if(REVDATAINFILE(f)) {
  4850. int i; /* RWD Feb 2010: should be OK as signed; too risky unsigned in a loop! */
  4851. if((buf = (char *) malloc((size_t) cnt)) == 0) { /*RWD 2007 */
  4852. rsferrno = ESFWRERR;
  4853. rsferrstr = "Write error: can't allocate byte swap buffer";
  4854. return -1;
  4855. }
  4856. switch(containersize) {
  4857. char *p_byte;
  4858. char *p_buf;
  4859. case 16:
  4860. ssp = (short *)outbuf;
  4861. sdp = (short *)buf;
  4862. for(i = cnt/sizeof(short); i > 0; i--) {
  4863. *sdp = REVWBYTES(*ssp);
  4864. ssp++;
  4865. sdp++;
  4866. }
  4867. break;
  4868. case 32:
  4869. dsp = (DWORD *)outbuf;
  4870. ddp = (DWORD *)buf;
  4871. for(i = cnt/sizeof(DWORD); i > 0; i--) {
  4872. *ddp = REVDWBYTES(*dsp);
  4873. dsp++;
  4874. ddp++;
  4875. }
  4876. break;
  4877. //case 20:
  4878. case 24:
  4879. p_byte = outbuf;
  4880. p_buf = buf;
  4881. for(i= cnt/3; i > 0; i--){
  4882. p_buf[0] = p_byte[2];
  4883. p_buf[1] = p_byte[1];
  4884. p_buf[2] = p_byte[0];
  4885. p_byte += 3;
  4886. p_buf += 3;
  4887. }
  4888. break;
  4889. default:
  4890. //abort();
  4891. rsferrno = ESFBADPARAM;
  4892. rsferrstr = "unsupported sample format";
  4893. if(buf != outbuf)
  4894. free(buf);
  4895. return -1;
  4896. break;
  4897. }
  4898. }
  4899. /* else creating file - max size */
  4900. if(dowrite(f, buf, (int) cnt)) {
  4901. rsferrno = ESFWRERR;
  4902. rsferrstr = "Write error";
  4903. if(buf != outbuf)
  4904. free(buf);
  4905. return -1;
  4906. }
  4907. f->curpos += (DWORD) cnt;
  4908. if(f->curpos > (DWORD) f->datachunksize) {
  4909. f->datachunksize = f->curpos;
  4910. f->infochanged = 1;
  4911. }
  4912. if(buf != outbuf)
  4913. free(buf);
  4914. return (int) cnt;
  4915. }
  4916. /* RWD PVX... maybe still need FILE64_WIN? */
  4917. //#ifdef FILE64_WIN
  4918. #ifdef _WIN32
  4919. /* RWD 2007 remember dist can be negative... */
  4920. __int64
  4921. sfseek_buffered(int sfd, __int64 dist, int whence)
  4922. {
  4923. struct sf_file *f;
  4924. __int64 newpos = 0;
  4925. __int64 i64size;
  4926. LARGE_INTEGER pos64;
  4927. if((f = findfile(sfd)) == 0)
  4928. return -1;
  4929. i64size = sfsize(sfd); /* NB Can't fail! */ //RWD OCT97: NB: assumes file of SHORTS or FLOATS
  4930. switch(whence) {
  4931. case 0:
  4932. newpos = dist;
  4933. break;
  4934. case 1:
  4935. newpos = (__int64) f->curpos + dist;
  4936. break;
  4937. case 2:
  4938. newpos = i64size + dist;
  4939. break;
  4940. default:
  4941. rsferrno = ESFBADPARAM;
  4942. rsferrstr = "illegal whence value in sfseek";
  4943. break;
  4944. }
  4945. if(newpos < 0)
  4946. newpos = 0;
  4947. if(newpos > i64size)
  4948. newpos = i64size;
  4949. f->curpos = (unsigned int) newpos; //still size-specific here...
  4950. //RWD OCT97 must seek correctly in 8bit files
  4951. if(f->fmtchunkEx.Format.wBitsPerSample==8)
  4952. newpos /= 2;
  4953. newpos += f->datachunkoffset;
  4954. //#endif
  4955. #if defined _WIN32
  4956. pos64.QuadPart = newpos;
  4957. pos64.LowPart = SetFilePointer(f->fileno, pos64.LowPart,&pos64.HighPart, FILE_BEGIN);
  4958. if(pos64.LowPart==0xFFFFFFFF && GetLastError() != NO_ERROR){
  4959. /* != newpos) { */
  4960. rsferrno = ESFRDERR; //RWD CDP97
  4961. rsferrstr = "Seek error";
  4962. return -1;
  4963. }
  4964. if(pos64.QuadPart != newpos){
  4965. rsferrno = ESFRDERR;
  4966. rsferrstr = "Seek error";
  4967. return -1;
  4968. }
  4969. #else
  4970. if(lseek(f->fileno, newpos, SEEK_SET) != newpos) {
  4971. rsferrno = ESFRDERR; //RWD CDP97
  4972. rsferrstr = "Seek error";
  4973. return -1;
  4974. }
  4975. #endif
  4976. return f->curpos;
  4977. }
  4978. #else
  4979. __int64
  4980. sfseek_buffered(int sfd, __int64 dist, int whence)
  4981. {
  4982. struct sf_file *f;
  4983. __int64 newpos = 0; // allow max seek distance 2GB
  4984. __int64 size;
  4985. fpos_t bytepos;
  4986. if((f = findfile(sfd)) == 0)
  4987. //return -1;
  4988. return 0xFFFFFFFF;
  4989. size = sfsize(sfd); /* NB Can't fail! */ //RWD OCT97: NB: assumes file of SHORTS or FLOATS
  4990. switch(whence) {
  4991. case 0:
  4992. newpos = dist;
  4993. break;
  4994. case 1:
  4995. newpos = f->curpos + dist;
  4996. break;
  4997. case 2:
  4998. newpos = size + dist;
  4999. break;
  5000. default:
  5001. rsferrno = ESFBADPARAM;
  5002. rsferrstr = "illegal whence value in sfseek";
  5003. break;
  5004. }
  5005. if(newpos < 0)
  5006. newpos = 0;
  5007. if(newpos > size)
  5008. newpos = size;
  5009. f->curpos = (DWORD) newpos; //still size-specific here...
  5010. //RWD OCT97 must seek correctly in 8bit files
  5011. if(f->fmtchunkEx.Format.wBitsPerSample==8)
  5012. newpos /= 2;
  5013. //
  5014. //#endif
  5015. #if defined _WIN32
  5016. newpos += f->datachunkoffset;
  5017. if(SetFilePointer(f->fileno, newpos,NULL, FILE_BEGIN) != newpos) {
  5018. #else
  5019. POS64(bytepos) = (DWORD) newpos + POS64(f->datachunkoffset);
  5020. if(fsetpos(f->fileno, &bytepos)) {
  5021. #endif
  5022. rsferrno = ESFRDERR; //RWD CDP97
  5023. rsferrstr = "Seek error";
  5024. return -1;
  5025. }
  5026. return (__int64) f->curpos;
  5027. }
  5028. #endif
  5029. //RWD: this may not be sufficient: we may want to distinguish betweeen
  5030. // float sfiles and analfiles....
  5031. static int
  5032. wavupdate(struct sf_file *f)
  5033. {
  5034. unsigned long seekdist;
  5035. fpos_t bytepos;
  5036. switch(f->fmtchunkEx.Format.wBitsPerSample) {
  5037. case 8:
  5038. f->fmtchunkEx.Format.nAvgBytesPerSec = f->fmtchunkEx.Format.nBlockAlign = f->fmtchunkEx.Format.nChannels;
  5039. f->datachunksize /= 2;
  5040. break;
  5041. case 16:
  5042. f->fmtchunkEx.Format.nAvgBytesPerSec = f->fmtchunkEx.Format.nBlockAlign = f->fmtchunkEx.Format.nChannels * 2;
  5043. break;
  5044. case 32:
  5045. f->fmtchunkEx.Format.nAvgBytesPerSec = f->fmtchunkEx.Format.nBlockAlign = f->fmtchunkEx.Format.nChannels * 4;
  5046. f->fmtchunkEx.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; //RWD 07:97
  5047. //RWD TODO: update 'fact' chunk with num-samples
  5048. break;
  5049. default:
  5050. abort();
  5051. }
  5052. f->fmtchunkEx.Format.nAvgBytesPerSec *= f->fmtchunkEx.Format.nSamplesPerSec;
  5053. //add space for fact chunk ?
  5054. //WARNING: THIS HAS NOT BEEN FULLY TESTED!
  5055. // maxsamp needed this...writes directly to existing header on disk
  5056. //f->extrachunksizes = 3*sizeof(DWORD);
  5057. f->mainchunksize = POS64(f->datachunkoffset) + (DWORD) f->datachunksize - 2*sizeof(DWORD) + f->extrachunksizes;
  5058. #if defined _WIN32
  5059. if(SetFilePointer(f->fileno, 4L,NULL, FILE_BEGIN)== 0xFFFFFFFF
  5060. #else
  5061. if(fseek(f->fileno, 4L, SEEK_SET) < 0
  5062. #endif
  5063. || write_dw_lsf(f->mainchunksize, f)
  5064. #if defined _WIN32
  5065. || SetFilePointer(f->fileno, f->fmtchunkoffset,NULL, FILE_BEGIN)== 0xFFFFFFFF
  5066. || write_w_lsf(f->fmtchunkEx.Format.wFormatTag, f)
  5067. || write_w_lsf(f->fmtchunkEx.Format.nChannels, f)
  5068. || write_dw_lsf(f->fmtchunkEx.Format.nSamplesPerSec, f)
  5069. || write_dw_lsf(f->fmtchunkEx.Format.nAvgBytesPerSec, f)
  5070. || write_w_lsf(f->fmtchunkEx.Format.nBlockAlign, f)
  5071. || write_w_lsf(f->fmtchunkEx.Format.wBitsPerSample, f)){
  5072. rsferrno = ESFWRERR;
  5073. rsferrstr = "Write error: Can't update format data";
  5074. return -1;
  5075. }
  5076. #else
  5077. || fsetpos(f->fileno, &f->fmtchunkoffset)
  5078. || write_w_lsf(f->fmtchunkEx.Format.wFormatTag, f)
  5079. || write_w_lsf(f->fmtchunkEx.Format.nChannels, f)
  5080. || write_dw_lsf(f->fmtchunkEx.Format.nSamplesPerSec, f)
  5081. || write_dw_lsf(f->fmtchunkEx.Format.nAvgBytesPerSec, f)
  5082. || write_w_lsf(f->fmtchunkEx.Format.nBlockAlign, f)
  5083. || write_w_lsf(f->fmtchunkEx.Format.wBitsPerSample, f)){
  5084. rsferrno = ESFWRERR;
  5085. rsferrstr = "Write error: Can't update format data";
  5086. return -1;
  5087. }
  5088. #endif
  5089. //RWD OCT97: the extra cbSize field SHOULD be there, = 0
  5090. //fact chunk contains size in samples
  5091. if(f->fmtchunkEx.Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT){
  5092. if(POS64(f->factchunkoffset) > 0){ /*RWD 01:2004 */
  5093. #if defined _WIN32
  5094. if(SetFilePointer(f->fileno,f->factchunkoffset,NULL,FILE_BEGIN)== 0xFFFFFFFF
  5095. #else
  5096. if(fsetpos(f->fileno,&f->factchunkoffset)
  5097. #endif
  5098. ||write_dw_lsf((DWORD)(f->datachunksize / (f->fmtchunkEx.Format.wBitsPerSample / sizeof(char))),f)){ /*RWD 2007 */
  5099. rsferrno = ESFWRERR;
  5100. rsferrstr = "Write error: Can't update fact chunk for floatsam data";
  5101. return -1;
  5102. }
  5103. }
  5104. }
  5105. #if defined _WIN32
  5106. if(SetFilePointer(f->fileno, f->datachunkoffset - sizeof(DWORD),NULL, FILE_BEGIN)== 0xFFFFFFFF
  5107. #else
  5108. seekdist = POS64(f->datachunkoffset) - sizeof(DWORD);
  5109. POS64(bytepos) = seekdist;
  5110. if(fsetpos(f->fileno, &bytepos)
  5111. #endif
  5112. ||write_dw_lsf((DWORD) f->datachunksize, f) ) { /*RWD 2007 */
  5113. rsferrno = ESFWRERR;
  5114. rsferrstr = "Write error: Can't update data size";
  5115. return -1;
  5116. }
  5117. return 0;
  5118. }
  5119. /******* SFSY98 VERSION*******
  5120. ******* main format data already there - just update durations
  5121. */
  5122. //RWD.5.99 TODO: need to be more clever with extended formats:
  5123. //must distinguish 32bit int and float
  5124. //this is used when header has already been set
  5125. static int
  5126. wavupdate98(time_t thistime, struct sf_file *f)
  5127. {
  5128. fpos_t bytepos;
  5129. if(! f->header_set)
  5130. return -1;
  5131. if(f->fmtchunkEx.Format.wBitsPerSample == 8)
  5132. f->datachunksize /= 2;
  5133. f->mainchunksize = POS64(f->datachunkoffset) + (DWORD) f->datachunksize - 2*sizeof(DWORD) + f->extrachunksizes;
  5134. #if defined _WIN32
  5135. if(SetFilePointer(f->fileno, 4L,NULL, FILE_BEGIN)== 0xFFFFFFFF
  5136. #else
  5137. if(fseek(f->fileno, 4L, SEEK_SET) < 0
  5138. #endif
  5139. ||write_dw_lsf(f->mainchunksize, f)){
  5140. rsferrno = ESFWRERR;
  5141. rsferrstr = "SFSY98: Write error: Can't update datachunk size";
  5142. return -1;
  5143. }
  5144. #ifdef NOTDEF
  5145. if(f->infochanged){
  5146. #ifdef _WIN32
  5147. if(SetFilePointer(f->fileno, f->fmtchunkoffset,NULL, FILE_BEGIN)== 0xFFFFFFFF
  5148. #else
  5149. if(fsetpos(f->fileno, &f->fmtchunkoffset)
  5150. #endif
  5151. ||write_w_lsf(f->fmtchunkEx.Format.wFormatTag, f)
  5152. ||write_w_lsf(f->fmtchunkEx.Format.nChannels, f)
  5153. ||write_dw_lsf(f->fmtchunkEx.Format.nSamplesPerSec, f)
  5154. ||write_dw_lsf(f->fmtchunkEx.Format.nAvgBytesPerSec, f)
  5155. ||write_w_lsf(f->fmtchunkEx.Format.nBlockAlign, f)
  5156. ||write_w_lsf(f->fmtchunkEx.Format.wBitsPerSample, f)){
  5157. rsferrno = ESFWRERR;
  5158. rsferrstr = "SFSYS98: Write error: Can't update chunk sizes or info chunk";
  5159. return -1;
  5160. }
  5161. }
  5162. #endif
  5163. if(f->fmtchunkEx.Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT){
  5164. //fact chunk contains size in samples
  5165. //RWD.5.99 may not be using it...
  5166. if(POS64(f->factchunkoffset) > 0){
  5167. #if defined _WIN32
  5168. if(SetFilePointer(f->fileno,f->factchunkoffset,NULL,FILE_BEGIN)== 0xFFFFFFFF
  5169. #else
  5170. if(fsetpos(f->fileno,&f->factchunkoffset)
  5171. #endif
  5172. || write_dw_lsf((DWORD)(f->datachunksize / (f->fmtchunkEx.Format.wBitsPerSample / sizeof(char))),f)) {
  5173. rsferrno = ESFWRERR;
  5174. rsferrstr = "SFSYS98: Write error: Can't update fact chunk for floatsam file";
  5175. return -1;
  5176. }
  5177. }
  5178. }
  5179. //RWD.6.5.99 update peak chunk
  5180. if((f->min_header >= SFILE_PEAKONLY) && f->peaks){
  5181. #if defined _WIN32
  5182. if(SetFilePointer(f->fileno,f->peakchunkoffset + sizeof(DWORD),NULL,FILE_BEGIN)== 0xFFFFFFFF
  5183. #else
  5184. fpos_t target = f->peakchunkoffset;
  5185. POS64(target) += sizeof(DWORD);
  5186. //if(lseek(f->fileno,f->peakchunkoffset + sizeof(DWORD),SEEK_SET) < 0
  5187. if(fsetpos(f->fileno,&target)
  5188. #endif
  5189. || write_dw_lsf((DWORD) thistime,f)
  5190. || write_peak_lsf(f->fmtchunkEx.Format.nChannels,f)) {
  5191. rsferrno = ESFWRERR;
  5192. rsferrstr = "SFSYS98: Write error: Can't update peak chunk";
  5193. return -1;
  5194. }
  5195. }
  5196. #if defined _WIN32
  5197. if(SetFilePointer(f->fileno, f->datachunkoffset - sizeof(DWORD),NULL, FILE_BEGIN)== 0xFFFFFFFF
  5198. ||write_dw_lsf((DWORD) f->datachunksize, f) ) {
  5199. #else
  5200. bytepos = f->datachunkoffset;
  5201. POS64(bytepos) -= sizeof(DWORD);
  5202. //if(lseek(f->fileno, f->datachunkoffset - sizeof(DWORD), SEEK_SET) < 0
  5203. // ||write_dw_lsf((DWORD) f->datachunksize, f) ) {
  5204. if(fsetpos(f->fileno, &bytepos)
  5205. ||write_dw_lsf((DWORD) f->datachunksize, f) ) {
  5206. #endif
  5207. rsferrno = ESFWRERR;
  5208. rsferrstr = "SFSYS98: Write error: Can't update chunk sizes or info chunk";
  5209. return -1;
  5210. }
  5211. return 0;
  5212. }
  5213. static int
  5214. aiffupdate(time_t thistime,struct sf_file *f)
  5215. {
  5216. DWORD numsampleframes;
  5217. fpos_t bytepos;
  5218. struct aiffchunk *ap = f->aiffchunks;
  5219. int commafterdata = 0;
  5220. switch(f->fmtchunkEx.Format.wBitsPerSample) {
  5221. case 8:
  5222. f->datachunksize /= 2;
  5223. numsampleframes = (DWORD) f->datachunksize; /* RWD 2007 added DWORD casts */
  5224. break;
  5225. case 16:
  5226. numsampleframes = (DWORD) f->datachunksize / 2;
  5227. break;
  5228. case 32:
  5229. numsampleframes = (DWORD) f->datachunksize / 4;
  5230. break;
  5231. default:
  5232. abort();
  5233. }
  5234. numsampleframes /= f->fmtchunkEx.Format.nChannels;
  5235. f->mainchunksize = sizeof(DWORD) + 2*sizeof(DWORD) + 26 + 2*sizeof(DWORD) + (DWORD)(f->datachunksize + f->extrachunksizes);
  5236. #if defined _WIN32
  5237. if(SetFilePointer(f->fileno,4L,NULL,FILE_BEGIN) == 0xFFFFFFFF
  5238. ||write_dw_msf((DWORD) POS64(f->mainchunksize), f)
  5239. ||SetFilePointer(f->fileno,(long)(POS64(f->datachunkoffset) - 3*sizeof(DWORD)),NULL,FILE_BEGIN) == 0xFFFFFFFF
  5240. ||write_dw_msf((DWORD)(f->datachunksize + 2*sizeof(DWORD)), f) ) {
  5241. rsferrno = ESFWRERR;
  5242. rsferrstr = "Write error: Can't update main or data chunk size";
  5243. return -1;
  5244. }
  5245. #else
  5246. bytepos = f->datachunkoffset;
  5247. POS64(bytepos) -= 3 * sizeof(DWORD);
  5248. if(fseek(f->fileno, 4L, SEEK_SET)
  5249. ||write_dw_msf((DWORD) f->mainchunksize, f)
  5250. ||fsetpos(f->fileno, &bytepos)
  5251. ||write_dw_msf((DWORD)(f->datachunksize + 2*sizeof(DWORD)), f) ) {
  5252. rsferrno = ESFWRERR;
  5253. rsferrstr = "Write error: Can't update main or data chunk size";
  5254. return -1;
  5255. }
  5256. #endif
  5257. if(POS64(f->fmtchunkoffset) > POS64(f->datachunkoffset)) {
  5258. commafterdata++;
  5259. POS64(f->fmtchunkoffset) = POS64(f->datachunkoffset) + (DWORD)( (f->datachunksize+1)&~1);
  5260. }
  5261. //RWD NB no support for AIFC here...
  5262. #ifdef NOTDEF
  5263. else
  5264. f->fmtchunkoffset -= 2*sizeof(DWORD);
  5265. #endif
  5266. #if defined _WIN32
  5267. if(SetFilePointer(f->fileno,f->fmtchunkoffset,NULL,FILE_BEGIN) == 0xFFFFFFFF){
  5268. #else
  5269. if(fsetpos(f->fileno, &f->fmtchunkoffset) ) {
  5270. #endif
  5271. rsferrno = ESFWRERR;
  5272. rsferrstr = "Write error: Can't seek to COMM chunk";
  5273. return -1;
  5274. }
  5275. if(
  5276. #ifdef NOTDEF
  5277. write_dw_msf(TAG('C','O','M','M'), f)
  5278. ||write_dw_msf(18, f)
  5279. ||
  5280. #endif
  5281. write_w_msf(f->fmtchunkEx.Format.nChannels, f)
  5282. ||write_dw_msf(numsampleframes, f)
  5283. ||write_w_msf(f->fmtchunkEx.Format.wBitsPerSample, f)
  5284. ||write_dw_toex(f->fmtchunkEx.Format.nSamplesPerSec, f) ) {
  5285. rsferrno = ESFWRERR;
  5286. rsferrstr = "Write error: Can't update COMM chunk";
  5287. return -1;
  5288. }
  5289. //RWD.6.5.99 update peak chunk
  5290. if((f->min_header >= SFILE_PEAKONLY) && f->peaks){
  5291. #if defined _WIN32
  5292. if(SetFilePointer(f->fileno,f->peakchunkoffset + sizeof(DWORD),NULL,FILE_BEGIN)== 0xFFFFFFFF
  5293. #else
  5294. bytepos = f->peakchunkoffset;
  5295. POS64(bytepos) += sizeof(DWORD);
  5296. if(fsetpos(f->fileno,&bytepos)
  5297. #endif
  5298. || write_dw_msf((DWORD) thistime,f)
  5299. || write_peak_msf(f->fmtchunkEx.Format.nChannels,f)) {
  5300. rsferrno = ESFWRERR;
  5301. rsferrstr = "SFSYS98: Write error: Can't update peak chunk";
  5302. return -1;
  5303. }
  5304. }
  5305. if(!commafterdata) {
  5306. #if defined _WIN32
  5307. if(SetFilePointer(f->fileno,(long)(f->datachunkoffset + (f->datachunksize+1)&~1),NULL,FILE_BEGIN)==0xFFFFFFFF) {
  5308. #else
  5309. bytepos = f->datachunkoffset;
  5310. POS64(bytepos) += (f->datachunksize+1)&~1;
  5311. if(fsetpos(f->fileno, &bytepos) ) {
  5312. #endif
  5313. rsferrno = ESFWRERR;
  5314. rsferrstr = "Can't seek to end, to update extra chunks";
  5315. return -1;
  5316. }
  5317. }
  5318. for(; ap != 0; ap = ap->next) {
  5319. if(POS64(ap->offset) < POS64(f->datachunkoffset))
  5320. continue;
  5321. if(write_dw_msf(ap->tag, f)
  5322. ||write_dw_msf(ap->size, f)
  5323. ||dowrite(f, ap->buf, (ap->size+1)&~1) ) {
  5324. rsferrno = ESFWRERR;
  5325. rsferrstr = "Can't update extra chunk";
  5326. return -1;
  5327. }
  5328. }
  5329. return 0;
  5330. }
  5331. static int
  5332. aiffupdate98(time_t thistime,struct sf_file *f)
  5333. {
  5334. DWORD numsampleframes = 0;
  5335. #ifdef linux
  5336. fpos_t bytepos = {0};
  5337. #else
  5338. fpos_t bytepos = 0;
  5339. #endif
  5340. struct aiffchunk *ap = f->aiffchunks;
  5341. int commafterdata = 0;
  5342. if(! f->header_set)
  5343. return -1;
  5344. if(f->infochanged){
  5345. switch(f->fmtchunkEx.Format.wBitsPerSample) {
  5346. case 8:
  5347. f->datachunksize /= 2;
  5348. numsampleframes = (DWORD) f->datachunksize;
  5349. break;
  5350. case 16:
  5351. numsampleframes = (DWORD) f->datachunksize/2;
  5352. break;
  5353. case 20: //NB not allowed by AIFF - no header field for masked sizes
  5354. case 24:
  5355. numsampleframes = (DWORD) f->datachunksize / 3;
  5356. break;
  5357. case 32:
  5358. numsampleframes = (DWORD) f->datachunksize/4;
  5359. break;
  5360. default:
  5361. rsferrno = ESFBADPARAM;
  5362. rsferrstr = "cannot update with unknown sample format";
  5363. return -1;
  5364. break;
  5365. }
  5366. }
  5367. // else if bitspersample== 8.... ?
  5368. numsampleframes /= f->fmtchunkEx.Format.nChannels;
  5369. /* RWD 8.99 this may be wrong...*/
  5370. /*f->mainchunksize = sizeof(DWORD) + 2*sizeof(DWORD) + 26 + 2*sizeof(DWORD) + f->datachunksize + f->extrachunksizes;
  5371. */
  5372. f->mainchunksize = POS64(f->datachunkoffset) + (DWORD) f->datachunksize - 2 * sizeof(DWORD);
  5373. #if defined _WIN32
  5374. if(SetFilePointer(f->fileno,4L,NULL,FILE_BEGIN) == 0xFFFFFFFF
  5375. #else
  5376. bytepos = f->datachunkoffset;
  5377. POS64(bytepos) -= 3*sizeof(DWORD);
  5378. if(fseek(f->fileno, 4L, SEEK_SET) < 0
  5379. #endif
  5380. ||write_dw_msf(f->mainchunksize, f)
  5381. #if defined _WIN32
  5382. ||SetFilePointer(f->fileno,(long)(f->datachunkoffset - 3*sizeof(DWORD)),NULL,FILE_BEGIN) == 0xFFFFFFFF
  5383. #else
  5384. // ||lseek(f->fileno, f->datachunkoffset - 3*sizeof(DWORD), SEEK_SET) < 0
  5385. ||fsetpos(f->fileno, &bytepos)
  5386. #endif
  5387. ||write_dw_msf((DWORD) f->datachunksize + 2*sizeof(DWORD), f) ) {
  5388. rsferrno = ESFWRERR;
  5389. rsferrstr = "Write error: Can't update main or data chunk size";
  5390. return -1;
  5391. }
  5392. if(POS64(f->fmtchunkoffset) > POS64(f->datachunkoffset)) {
  5393. commafterdata++;
  5394. POS64(f->fmtchunkoffset) = POS64(f->datachunkoffset) + (DWORD)((f->datachunksize+1)&~1); /*RWD 2007 */
  5395. }
  5396. //RWD don't want to do this - might be AIFC - don't need to anyway!
  5397. #ifdef NOTDEF
  5398. else
  5399. f->fmtchunkoffset -= 2*sizeof(DWORD);
  5400. #endif
  5401. #if defined _WIN32
  5402. if(SetFilePointer(f->fileno,f->fmtchunkoffset,NULL,FILE_BEGIN) == 0xFFFFFFFF){
  5403. #else
  5404. if(fsetpos(f->fileno, &f->fmtchunkoffset) ) {
  5405. #endif
  5406. rsferrno = ESFWRERR;
  5407. rsferrstr = "Write error: Can't seek to COMM chunk";
  5408. return -1;
  5409. }
  5410. //strictly, we should check the new format and redo the AIFC stuff,
  5411. //OR reject if infochanged
  5412. //at least, disallow format conversion in AIFC!
  5413. if(
  5414. #ifdef NOTDEF
  5415. write_dw_msf(TAG('C','O','M','M'), f)
  5416. ||write_dw_msf(18, f)
  5417. ||
  5418. #endif
  5419. write_w_msf(f->fmtchunkEx.Format.nChannels, f)
  5420. ||write_dw_msf(numsampleframes, f)
  5421. ||write_w_msf(f->fmtchunkEx.Format.wBitsPerSample, f)
  5422. ||write_dw_toex(f->fmtchunkEx.Format.nSamplesPerSec, f) ) {
  5423. rsferrno = ESFWRERR;
  5424. rsferrstr = "Write error: Can't update COMM chunk";
  5425. return -1;
  5426. }
  5427. // update peak chunk
  5428. if((f->min_header >= SFILE_PEAKONLY) && f->peaks){
  5429. #if defined _WIN32
  5430. if(SetFilePointer(f->fileno,f->peakchunkoffset + sizeof(DWORD),NULL,FILE_BEGIN)== 0xFFFFFFFF
  5431. #else
  5432. bytepos = f->peakchunkoffset;
  5433. POS64(bytepos) += sizeof(DWORD);
  5434. if(fsetpos(f->fileno,&bytepos)
  5435. #endif
  5436. || write_dw_msf((DWORD) thistime,f)
  5437. || write_peak_msf(f->fmtchunkEx.Format.nChannels,f)) {
  5438. rsferrno = ESFWRERR;
  5439. rsferrstr = "SFSYS98: Write error: Can't update peak chunk";
  5440. return -1;
  5441. }
  5442. }
  5443. if(!commafterdata) {
  5444. #if defined _WIN32
  5445. if(SetFilePointer(f->fileno,(long)(f->datachunkoffset + (f->datachunksize+1)&~1),NULL,FILE_BEGIN)==0xFFFFFFFF) {
  5446. #else
  5447. bytepos = f->datachunkoffset;
  5448. POS64(bytepos) += (f->datachunksize+1)&~1;
  5449. // if(lseek(f->fileno, f->datachunkoffset + (f->datachunksize+1)&~1, SEEK_SET) < 0) {
  5450. if(fsetpos(f->fileno, &bytepos) ) {
  5451. #endif
  5452. rsferrno = ESFWRERR;
  5453. rsferrstr = "Can't seek to end, to update extra chunks";
  5454. return -1;
  5455. }
  5456. }
  5457. /* RWD: NB if we have these, they will start correctly after a pad byte,
  5458. * and we will just trust that these chunks are kosher!*/
  5459. if(ap){
  5460. for(; ap != 0; ap = ap->next) {
  5461. if(POS64(ap->offset) < POS64(f->datachunkoffset))
  5462. continue;
  5463. if(write_dw_msf(ap->tag, f)
  5464. ||write_dw_msf(ap->size, f)
  5465. ||dowrite(f, ap->buf, (ap->size+1)&~1) ) {
  5466. rsferrno = ESFWRERR;
  5467. rsferrstr = "Can't update extra chunk";
  5468. return -1;
  5469. }
  5470. }
  5471. }
  5472. /*RWD AIFF requires pad byte at end, for 8bit and 24bit sample types*/
  5473. else {
  5474. #ifdef FILE64_WIN
  5475. __int64 size = f->datachunkoffset + (f->datachunksize+1)&~1;
  5476. #else
  5477. DWORD size = POS64(f->datachunkoffset) + ((f->datachunksize+1)&~1);
  5478. #endif
  5479. #if defined _WIN32
  5480. if(w_ch_size(f->fileno, size) < 0) {
  5481. #else
  5482. if(ftruncate(fileno(f->fileno), (off_t) size) < 0) {
  5483. #endif
  5484. rsferrno = ESFWRERR;
  5485. rsferrstr = "write error truncating file";
  5486. return -1;
  5487. }
  5488. }
  5489. return 0;
  5490. }
  5491. int
  5492. sfclose(int sfd)
  5493. {
  5494. struct sf_file *f;
  5495. int rc = 0;
  5496. if((f = findfile(sfd)) == 0){ //RWD: may already have been closed... see errrmsg
  5497. rsferrstr = "SFSYS: close: bad file ID (already closed?)";
  5498. return -1;
  5499. }
  5500. #ifdef ENABLE_PVX
  5501. if(f->pvxprops != NULL){
  5502. //either readonly input file, or new output file. If latter, must fill in analysis fields from sfprops
  5503. //including fmtx
  5504. //set pvxdata first, then set wfmt from that
  5505. if(!f->readonly) {
  5506. int origsize = 0,origrate=0,winlen=0,decfac=0;
  5507. float arate = 0.0;
  5508. int res;
  5509. //sfgetprop(int sfd, const char *propname, char *dest, int lim)
  5510. # ifdef _DEBUG
  5511. assert(f->pvxprops->nAnalysisBins > 0);
  5512. # endif
  5513. //ERROR! for pvx we want to get this from Format.wBitsPerSample
  5514. res = sfgetprop(sfd,"original sampsize",(char*) &origsize,sizeof(int));
  5515. if(res < 0){
  5516. # ifdef _DEBUG
  5517. fprintf(stderr,"error from sfgetprop: original sampsize\n");
  5518. # endif
  5519. return -1;
  5520. }
  5521. else
  5522. // fprintf(stderr, "sfclose: got original sampsize = %d\n",origsize);
  5523. res = sfgetprop(sfd,"original sample rate",(char*) &origrate,sizeof(int));
  5524. if(res < 0){
  5525. // fprintf(stderr,"error from sfgetprop: original samplerate\n");
  5526. return -1;
  5527. }
  5528. else
  5529. // fprintf(stderr, "sfclose: got original sample rate = %d\n",origrate);
  5530. res = sfgetprop(sfd,"arate",(char*) &arate,sizeof(float));
  5531. if(res < 0){
  5532. // fprintf(stderr,"error from sfgetprop: arate\n");
  5533. return -1;
  5534. }
  5535. else
  5536. // fprintf(stderr, "sfclose: got arate = %f\n",arate);
  5537. res = sfgetprop(sfd,"analwinlen",(char*) &winlen,sizeof(int));
  5538. res = sfgetprop(sfd,"decfactor",(char*) &decfac,sizeof(int));
  5539. //this comes from dz->infile->stype
  5540. switch(origsize){
  5541. case SAMP_SHORT:
  5542. f->fmtchunkEx.Format.wBitsPerSample = 16;
  5543. break;
  5544. case SAMP_2024:
  5545. case SAMP_2424:
  5546. f->fmtchunkEx.Format.wBitsPerSample = 24;
  5547. break;
  5548. case SAMP_LONG:
  5549. case SAMP_FLOAT:
  5550. f->fmtchunkEx.Format.wBitsPerSample = 32;
  5551. }
  5552. f->pvxprops->wWordFormat = PVOC_IEEE_FLOAT; /* no plans for a doubles implementation yet */
  5553. f->pvxprops->wAnalFormat = PVOC_AMP_FREQ;
  5554. f->pvxprops->wSourceFormat = origsize == SAMP_FLOAT ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM;
  5555. f->pvxprops->wWindowType = /* probably*/ PVOC_HANN; /* whatever is set in CDP pvoc these days */
  5556. f->pvxprops->fAnalysisRate = arate;
  5557. /* we already have nAnalysisBins, can't change that anyway */
  5558. f->pvxprops->dwWinlen = winlen;
  5559. f->pvxprops->dwOverlap = decfac;
  5560. f->fmtchunkEx.Format.nSamplesPerSec = origrate;
  5561. f->fmtchunkEx.Format.nChannels = 1;
  5562. // f->fmtchunkEx.Format.wBitsPerSample = 32;
  5563. f->fmtchunkEx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
  5564. f->fmtchunkEx.Format.nBlockAlign = f->fmtchunkEx.Format.nChannels * sizeof(float);
  5565. f->fmtchunkEx.Format.nAvgBytesPerSec =f->fmtchunkEx.Format.nBlockAlign * f->fmtchunkEx.Format.nSamplesPerSec;
  5566. f->fmtchunkEx.Format.cbSize = 62;
  5567. f->filetype = riffwav;
  5568. }
  5569. if((rc = pvoc_update_closefile(f->pvxfileno,f->pvxprops,&f->fmtchunkEx)) < 0){
  5570. #ifdef _DEBUG
  5571. fprintf(stderr,"sfclose: can't close pvx file\n");
  5572. #endif
  5573. return -1;
  5574. }
  5575. else {
  5576. // fprintf(stderr,"pvx file closed OK!\n");
  5577. freesffile(sfd-SFDBASE);
  5578. }
  5579. return rc;
  5580. }
  5581. /* RWD TODO: handle f->todelete, typically set by call to sfunlink(sfd) */
  5582. #endif
  5583. if((f->infochanged || f->propschanged) && !f->todelete && !f->readonly) {
  5584. unsigned int cdptime;
  5585. time_t now = time(0);
  5586. cdptime = (unsigned int) now;
  5587. //RWD.5.99
  5588. if((f->min_header >= SFILE_CDP) && POS64(f->propoffset) > 0)
  5589. sfputprop(sfd, "DATE", /* (char *)&now */ (char *) &cdptime, sizeof(/*long*/int));
  5590. switch(f->filetype) {
  5591. case riffwav:
  5592. case wave_ex:
  5593. if(f->header_set)
  5594. rc = wavupdate98(now,f); //RWD.6.5.99
  5595. else
  5596. rc = wavupdate(f);
  5597. break;
  5598. case eaaiff:
  5599. case aiffc:
  5600. if(f->header_set)
  5601. rc = aiffupdate98(now,f);
  5602. else
  5603. rc = aiffupdate(now,f); //RWD.6.5.99
  5604. break;
  5605. default:
  5606. //abort();
  5607. rsferrno = ESFBADPARAM;
  5608. rsferrstr = "SFSYS98: aif-c files not supported";
  5609. return -1;
  5610. break;
  5611. }
  5612. f->propschanged = 1;
  5613. }
  5614. if(f->min_header >= SFILE_CDP && POS64(f->propoffset) >= 0 && f->propschanged && !f->todelete && !f->readonly)
  5615. if(writeprops(f) < 0)
  5616. rc = -1;
  5617. #if defined _WIN32
  5618. if(!CloseHandle(f->fileno)) {
  5619. #else
  5620. if(fclose(f->fileno) < 0) {
  5621. #endif
  5622. rsferrno = ESFWRERR;
  5623. rsferrstr = "write error: system had trouble closing file";
  5624. rc = -1;
  5625. }
  5626. if(f->todelete
  5627. && f->filename != NULL
  5628. #if defined _WIN32
  5629. && !DeleteFile(f->filename)){
  5630. #else
  5631. && remove(f->filename) < 0) {
  5632. #endif
  5633. rsferrno = ESFWRERR;
  5634. rsferrstr = "can't remove soundfile";
  5635. rc = -1;
  5636. }
  5637. freesffile(sfd-SFDBASE);
  5638. return rc;
  5639. }
  5640. //return true size in bytes: of SHORTS or FLOATS file
  5641. __int64
  5642. sfsize(int sfd)
  5643. {
  5644. struct sf_file *f;
  5645. if((f = findfile(sfd)) == 0)
  5646. return -1;
  5647. return (__int64)(f->sizerequested == ES_EXIST ? f->datachunksize : f->sizerequested);
  5648. }
  5649. #ifdef FILE64_WIN
  5650. int
  5651. sfadjust(int sfd, __int64 delta)
  5652. {
  5653. struct sf_file *f;
  5654. __int64 newsize;
  5655. if(delta > 0) {
  5656. rsferrno = ESFBADPARAM;
  5657. rsferrstr = "Can't extend a soundfile";
  5658. return -1;
  5659. }
  5660. if((f = findfile(sfd)) == 0)
  5661. return -1;
  5662. if(f->readonly) {
  5663. rsferrno = ESFREADONLY;
  5664. rsferrstr = "can't adjust size of read-only file";
  5665. return -1;
  5666. }
  5667. f->infochanged = 1;
  5668. switch(f->sizerequested) {
  5669. case ES_EXIST:
  5670. if(f->datachunksize + delta < 0) {
  5671. rsferrno = ESFBADPARAM;
  5672. rsferrstr = "can't make soundfile with negative size";
  5673. return -1;
  5674. }
  5675. f->datachunksize += delta;
  5676. break;
  5677. default:
  5678. if(f->sizerequested + delta < 0) {
  5679. rsferrno = ESFBADPARAM;
  5680. rsferrstr = "can't make soundfile with negative size";
  5681. return -1;
  5682. }
  5683. if(f->sizerequested + delta >= f->datachunksize)
  5684. return 0;
  5685. f->sizerequested += delta;
  5686. f->datachunksize = f->sizerequested;
  5687. break;
  5688. }
  5689. newsize = f->datachunkoffset;
  5690. if(f->fmtchunkEx.Format.wBitsPerSample == 8)
  5691. newsize += f->datachunksize/2;
  5692. else
  5693. newsize += f->datachunksize;
  5694. #if defined _WIN32
  5695. if(w_ch_size(f->fileno, newsize) < 0) {
  5696. #else
  5697. if(chsize(f->fileno, newsize) < 0) {
  5698. #endif
  5699. rsferrno = ESFWRERR;
  5700. rsferrstr = "write error truncating file";
  5701. return -1;
  5702. }
  5703. return 0; /* is this right? */
  5704. }
  5705. #else
  5706. int
  5707. sfadjust(int sfd, __int64 delta)
  5708. {
  5709. struct sf_file *f;
  5710. __int64 newsize;
  5711. if(delta > 0) {
  5712. rsferrno = ESFBADPARAM;
  5713. rsferrstr = "Can't extend a soundfile";
  5714. return -1;
  5715. }
  5716. if((f = findfile(sfd)) == 0)
  5717. return -1;
  5718. if(f->readonly) {
  5719. rsferrno = ESFREADONLY;
  5720. rsferrstr = "can't adjust size of read-only file";
  5721. return -1;
  5722. }
  5723. f->infochanged = 1;
  5724. switch(f->sizerequested) {
  5725. case ES_EXIST:
  5726. if( f->datachunksize + delta < 0) {
  5727. rsferrno = ESFBADPARAM;
  5728. rsferrstr = "can't make soundfile with negative size";
  5729. return -1;
  5730. }
  5731. f->datachunksize += delta;
  5732. break;
  5733. default:
  5734. if(f->sizerequested + delta < 0) {
  5735. rsferrno = ESFBADPARAM;
  5736. rsferrstr = "can't make soundfile with negative size";
  5737. return -1;
  5738. }
  5739. if(f->sizerequested + delta >= f->datachunksize)
  5740. return 0;
  5741. f->sizerequested += delta;
  5742. f->datachunksize = f->sizerequested;
  5743. break;
  5744. }
  5745. newsize = (__int64) POS64(f->datachunkoffset);
  5746. if(f->fmtchunkEx.Format.wBitsPerSample == 8)
  5747. newsize += f->datachunksize/2;
  5748. else
  5749. newsize += f->datachunksize;
  5750. #if defined _WIN32
  5751. if(w_ch_size(f->fileno, newsize) < 0) {
  5752. #else
  5753. if(chsize(fileno(f->fileno), newsize) < 0) {
  5754. #endif
  5755. rsferrno = ESFWRERR;
  5756. rsferrstr = "write error truncating file";
  5757. return -1;
  5758. }
  5759. return 0; /* is this right? */
  5760. }
  5761. #endif
  5762. int
  5763. sfunlink(int sfd)
  5764. {
  5765. struct sf_file *f;
  5766. if((f = findfile(sfd)) == 0)
  5767. return -1;
  5768. if(f->readonly) {
  5769. rsferrno = ESFREADONLY;
  5770. rsferrstr = "can't delete read-only file";
  5771. return -1;
  5772. }
  5773. f->todelete = 1;
  5774. return 0;
  5775. }
  5776. int
  5777. sfrename(int sfd, const char *newname)
  5778. {
  5779. struct sf_file *f;
  5780. char *path = NULL;
  5781. if((f = findfile(sfd)) == 0)
  5782. return -1;
  5783. if(f->readonly) {
  5784. rsferrno = ESFREADONLY;
  5785. rsferrstr = "can't rename read-only file";
  5786. return -1;
  5787. }
  5788. if(f->filename == 0) {
  5789. rsferrno = ESFNOMEM;
  5790. rsferrstr = "Couldn't remember name of file";
  5791. return -1;
  5792. }
  5793. path = mksfpath(newname);
  5794. if(path==NULL){
  5795. rsferrno = ESFBADPARAM;
  5796. rsferrstr = "can't rename file changing its type";
  5797. return -1;
  5798. }
  5799. if(f->filetype != gettypefromname98(path)) {
  5800. rsferrno = ESFBADPARAM;
  5801. rsferrstr = "can't rename file changing its type";
  5802. return -1;
  5803. }
  5804. if(rename(f->filename, path) != 0) {
  5805. rsferrno = ESFDUPFNAME;
  5806. rsferrstr = "file already exists, or can't rename across devices";
  5807. return -1;
  5808. }
  5809. free(f->filename);
  5810. f->filename = _fullpath(NULL, path, 0);
  5811. return 0;
  5812. }
  5813. /*
  5814. * Property access routines
  5815. */
  5816. //RWD.6.99 mega-special case for sample type now!
  5817. int
  5818. sfgetprop(int sfd, const char *propname, char *dest, int lim)
  5819. {
  5820. int lret = SAMP_MASKED; //RWD.6.99
  5821. int res,containersize;
  5822. struct sf_file *f;
  5823. struct property *pp;
  5824. if((f = findfile(sfd)) == 0)
  5825. return -1;
  5826. if(strcmp(propname, "channels") == 0)
  5827. lret = f->fmtchunkEx.Format.nChannels;
  5828. else if(strcmp(propname, "sample rate") == 0)
  5829. lret = f->fmtchunkEx.Format.nSamplesPerSec;
  5830. else if(strcmp(propname, "sample type") == 0) {
  5831. //RWD.6.99 lets accept all formats!
  5832. //is this good for AIFF?
  5833. //RWD 2025 fix this for pvx file with large fft size
  5834. //possible TODO: for analysis files, report src sample type, not just 'float'
  5835. if (f->filetype == pvxfile) {
  5836. containersize = sf_getcontainersize(sfd);
  5837. }
  5838. else {
  5839. containersize = 8 * (f->fmtchunkEx.Format.nBlockAlign / f->fmtchunkEx.Format.nChannels);
  5840. }
  5841. switch(containersize){
  5842. case(32):
  5843. if(f->fmtchunkEx.Format.wFormatTag== WAVE_FORMAT_IEEE_FLOAT
  5844. || (f->fmtchunkEx.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE
  5845. && (
  5846. (compare_guids(&(f->fmtchunkEx.SubFormat),&(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
  5847. ||
  5848. (compare_guids(&(f->fmtchunkEx.SubFormat),&(SUBTYPE_AMBISONIC_B_FORMAT_IEEE_FLOAT)))
  5849. )
  5850. )
  5851. ) {
  5852. lret = SAMP_FLOAT;
  5853. break;
  5854. }
  5855. else{
  5856. //int format: may be masked
  5857. switch(f->fmtchunkEx.Samples.wValidBitsPerSample){
  5858. case(32):
  5859. lret = SAMP_LONG;
  5860. break;
  5861. case(24):
  5862. lret = SAMP_2432;
  5863. break;
  5864. default:
  5865. lret = SAMP_MASKED;
  5866. break;
  5867. }
  5868. }
  5869. break;
  5870. case(24):
  5871. switch(f->fmtchunkEx.Samples.wValidBitsPerSample){
  5872. case(24):
  5873. lret = SAMP_2424;
  5874. break;
  5875. case(20):
  5876. lret = SAMP_2024;
  5877. break;
  5878. default:
  5879. lret = SAMP_MASKED;
  5880. break;
  5881. }
  5882. break;
  5883. case(16):
  5884. case(8):
  5885. lret = SAMP_SHORT;
  5886. break;
  5887. default:
  5888. break;
  5889. }
  5890. } else {
  5891. if(f->min_header < SFILE_CDP){
  5892. rsferrno = ESFNOTFOUND;
  5893. rsferrstr = "no CDP properties in minimum header";
  5894. return -1;
  5895. }
  5896. if(POS64(f->propoffset) >= 0)
  5897. for(pp = f->props; pp != 0; pp = pp->next) {
  5898. if(strcmp(propname, pp->name) == 0) {
  5899. res = min(pp->size, lim);
  5900. memcpy(dest, pp->data, res);
  5901. #ifdef ENABLE_PVX
  5902. # ifdef _DEBUG
  5903. // fprintf(stderr,"sfgetprop: found prop %s\n",propname);
  5904. # endif
  5905. #endif
  5906. return res;
  5907. }
  5908. }
  5909. rsferrno = ESFNOTFOUND;
  5910. rsferrstr = "Property not defined in file";
  5911. #ifdef ENABLE_PVX
  5912. # ifdef _DEBUG
  5913. // fprintf(stderr,"failed to find property %s, propoffset = %lld\n",propname,POS64(f->propoffset));
  5914. # endif
  5915. #endif
  5916. return -1;
  5917. }
  5918. /*
  5919. * return a standard property as a long
  5920. */
  5921. res = min(lim, sizeof(int));
  5922. memcpy(dest, &lret, res);
  5923. return res;
  5924. }
  5925. static int
  5926. getlong(int *dest, char *src, int size, int error)
  5927. {
  5928. if(size != sizeof(int)) {
  5929. rsferrno = error;
  5930. rsferrstr = "Bad size for standard property";
  5931. return -1;
  5932. }
  5933. memcpy(dest, src, sizeof(int));
  5934. return 0;
  5935. }
  5936. //RWD.6.99 trap attempts to update primary properties of streamable file
  5937. // ATARI trapped, but ATARI ~could~ support 32bit longs, but who cares?
  5938. int
  5939. sfputprop(int sfd, char *propname, char *src, int size)
  5940. {
  5941. int data;
  5942. struct sf_file *f;
  5943. struct property *pp, **ppp;
  5944. char *np;
  5945. if((f = findfile(sfd)) == 0)
  5946. return -1;
  5947. if(f->readonly) {
  5948. rsferrno = ESFREADONLY;
  5949. rsferrstr = "can't set property in a read-only file";
  5950. return -1;
  5951. }
  5952. if(strcmp(propname, "channels") == 0) {
  5953. if(getlong(&data, src, size, ESFBADNCHANS) < 0)
  5954. return -1;
  5955. //RWD.6.99
  5956. if(f->header_set && (data != (int)f->fmtchunkEx.Format.nChannels)){
  5957. rsferrno = ESFBADPARAM;
  5958. rsferrstr = "not allowed to alter existing property";
  5959. return -1;
  5960. }
  5961. f->fmtchunkEx.Format.nChannels = (short)data;
  5962. f->infochanged = 1;
  5963. return 0;
  5964. } else if(strcmp(propname, "sample rate") == 0) {
  5965. if(getlong(&data, src, size, ESFBADRATE) < 0)
  5966. return -1;
  5967. //RWD.6.99
  5968. if(f->header_set && (data != (int) f->fmtchunkEx.Format.nSamplesPerSec)){
  5969. rsferrno = ESFBADPARAM;
  5970. rsferrstr = "not allowed to alter existing property";
  5971. return -1;
  5972. }
  5973. f->fmtchunkEx.Format.nSamplesPerSec = data;
  5974. f->infochanged = 1;
  5975. return 0;
  5976. } else if(strcmp(propname, "sample type") == 0) {
  5977. if(f->header_set){
  5978. rsferrno = ESFBADPARAM;
  5979. rsferrstr = "not allowed to alter existing property";
  5980. return -1;
  5981. }
  5982. if(getlong(&data, src, size, ESFBADPARAM) < 0)
  5983. return -1;
  5984. if(data < SAMP_SHORT && data >= SAMP_MASKED) {
  5985. rsferrno = ESFBADPARAM;
  5986. rsferrstr = "cannot change to unsupported sample type";
  5987. return -1;
  5988. }
  5989. if(f->fmtchunkEx.Format.wBitsPerSample == 8) {
  5990. rsferrno = ESFBADPARAM;
  5991. rsferrstr = "Can't change sample type when accessing 8 bits/sample file";
  5992. return -1;
  5993. }
  5994. switch(data){
  5995. case(SAMP_LONG):
  5996. case(SAMP_FLOAT):
  5997. case(SAMP_2432):
  5998. f->fmtchunkEx.Format.wBitsPerSample = 32;
  5999. break;
  6000. case(SAMP_2424):
  6001. case(SAMP_2024):
  6002. f->fmtchunkEx.Format.wBitsPerSample = 24;
  6003. break;
  6004. case(SAMP_SHORT):
  6005. f->fmtchunkEx.Format.wBitsPerSample = 16;
  6006. break;
  6007. case(SAMP_BYTE):
  6008. rsferrno = ESFBADPARAM;
  6009. rsferrstr = "8-bit files not supported for writing";
  6010. return -1;
  6011. default:
  6012. rsferrno = ESFBADPARAM;
  6013. rsferrstr = "cannot set unsupported sample type";
  6014. return -1;
  6015. break;
  6016. }
  6017. f->infochanged = 1;
  6018. return 0;
  6019. }
  6020. /*
  6021. * now deal with extended attributes
  6022. */
  6023. if((f->min_header < SFILE_CDP) || POS64(f->propoffset) < 0) {
  6024. rsferrno = ESFNOSPACE;
  6025. rsferrstr = "No property chunk in this .wav file";
  6026. return -1;
  6027. }
  6028. for(pp = f->props; pp != 0; pp = pp->next) {
  6029. if(strcmp(propname, pp->name) == 0) {
  6030. if(f->curpropsize + 2*(size - pp->size) > f->proplim) {
  6031. rsferrno = ESFNOSPACE;
  6032. rsferrstr = "No space in extended properties for bigger property data";
  6033. return -1;
  6034. }
  6035. if((np = (char *) malloc(size)) == 0) {
  6036. rsferrno = ESFNOMEM;
  6037. rsferrstr = "No memory for bigger property data";
  6038. return -1;
  6039. }
  6040. memcpy(np, src, size);
  6041. free(pp->data);
  6042. pp->data = np;
  6043. pp->size = size;
  6044. f->curpropsize -= 2*(size - pp->size);
  6045. f->propschanged = 1;
  6046. return 0;
  6047. }
  6048. }
  6049. /* adding new property */
  6050. if(f->curpropsize + (signed int)strlen(propname) + 2 + 2*size > f->proplim) {
  6051. rsferrno = ESFNOSPACE;
  6052. rsferrstr = "No space in extended properties for new property data";
  6053. return -1;
  6054. }
  6055. for(ppp = &f->props; *ppp != 0; ppp = &(*ppp)->next)
  6056. ;
  6057. if((*ppp = ALLOC(struct property)) == 0
  6058. ||((*ppp)->name = (char *) malloc(strlen(propname)+1)) == 0
  6059. ||((*ppp)->data = (char *) malloc(size)) == 0) {
  6060. rsferrno = ESFNOMEM;
  6061. rsferrstr = "No memory for bigger property data";
  6062. return -1;
  6063. }
  6064. strcpy((*ppp)->name, propname);
  6065. memcpy((*ppp)->data, src, size);
  6066. (*ppp)->size = size;
  6067. (*ppp)->next = 0;
  6068. f->curpropsize += strlen(propname) + 2 + 2*size;
  6069. f->propschanged = 1;
  6070. return 0;
  6071. }
  6072. //RWD.6.5.99 not used internally by header routines, return 0 for true
  6073. int sfputpeaks(int sfd,int channels,const CHPEAK peakdata[])
  6074. {
  6075. int i;
  6076. struct sf_file *f;
  6077. if((f = findfile(sfd)) == 0)
  6078. return -1;
  6079. if(f->readonly) {
  6080. rsferrno = ESFREADONLY;
  6081. rsferrstr = "can't set property in a read-only file";
  6082. return -1;
  6083. }
  6084. if(f->min_header < SFILE_PEAKONLY){
  6085. rsferrno = ESFNOSPACE;
  6086. rsferrstr = "no space for peak data in minimum header";
  6087. return -1;
  6088. }
  6089. if(f->peaks==NULL){
  6090. rsferrno = ESFREADONLY;
  6091. rsferrstr = "peak data not initialized";
  6092. return -1;
  6093. }
  6094. for(i=0;i < channels; i++){
  6095. f->peaks[i].value = peakdata[i].value;
  6096. f->peaks[i].position = peakdata[i].position;
  6097. }
  6098. return 0;
  6099. }
  6100. //NB this one not used internally by header routines, return 1 for true
  6101. int sfreadpeaks(int sfd,int channels,CHPEAK peakdata[],int *peaktime)
  6102. {
  6103. int i;
  6104. struct sf_file *f;
  6105. if((f = findfile(sfd)) == 0)
  6106. return -1;
  6107. if(f->peaks==NULL){ //NOT an error: just don't have the chunk
  6108. *peaktime = 0;
  6109. return 0;
  6110. }
  6111. *peaktime = (int) f->peaktime;
  6112. for(i=0;i < channels; i++){
  6113. peakdata[i].value = f->peaks[i].value;
  6114. peakdata[i].position = f->peaks[i].position;
  6115. }
  6116. return 1;
  6117. }
  6118. int
  6119. sfrmprop(int sfd, char *propname)
  6120. {
  6121. struct sf_file *f;
  6122. struct property **ppp;
  6123. if((f = findfile(sfd)) == 0)
  6124. return -1;
  6125. if(f->readonly) {
  6126. rsferrno = ESFREADONLY;
  6127. rsferrstr = "can't remove property from a read-only file";
  6128. return -1;
  6129. }
  6130. if(strcmp(propname, "channels") == 0
  6131. ||strcmp(propname, "sample rate") == 0
  6132. ||strcmp(propname, "sample type") == 0) {
  6133. rsferrno = ESFBADPARAM;
  6134. rsferrstr = "Cannot remove standard property";
  6135. return -1;
  6136. }
  6137. if(f->min_header < SFILE_CDP){
  6138. rsferrno = ESFNOTFOUND;
  6139. rsferrstr = "minimum header - no CDP properties present";
  6140. return -1;
  6141. }
  6142. if(POS64(f->propoffset) >= 0)
  6143. for(ppp = &f->props; *ppp != 0; ppp = &(*ppp)->next)
  6144. if(strcmp((*ppp)->name, propname) == 0) {
  6145. struct property *p = *ppp;
  6146. f->curpropsize -= strlen(propname) + 2 + p->size;
  6147. f->propschanged = 1;
  6148. free(p->name);
  6149. free(p->data);
  6150. *ppp = p->next;
  6151. free(p);
  6152. return 0;
  6153. }
  6154. rsferrno = ESFNOTFOUND;
  6155. rsferrstr = "Property not found";
  6156. return -1;
  6157. }
  6158. int
  6159. sfdirprop(int sfd, int (*func)(char *propname, int propsize))
  6160. {
  6161. struct sf_file *f;
  6162. struct property *pp;
  6163. if((f = findfile(sfd)) == 0)
  6164. return -1;
  6165. if(func("channels", sizeof( int)) != 0
  6166. ||func("sample type", sizeof( int)) != 0
  6167. ||func("sample rate", sizeof( int)) != 0)
  6168. return SFDIR_FOUND;
  6169. for(pp = f->props; pp != 0; pp = pp->next)
  6170. if(func(pp->name, pp->size) != 0)
  6171. return SFDIR_FOUND;
  6172. return SFDIR_NOTFOUND;
  6173. }
  6174. //CDP98
  6175. #if 0
  6176. static int asm_round(double fval)
  6177. {
  6178. int result;
  6179. _asm{
  6180. fld fval
  6181. fistp result
  6182. mov eax,result
  6183. }
  6184. return (long) result;
  6185. }
  6186. #endif
  6187. //RWD don't need this any more. "Deprecated".
  6188. int cdp_round(double fval)
  6189. {
  6190. return lround(fval);
  6191. }
  6192. int sfformat(int sfd, fileformat *pfmt)
  6193. {
  6194. struct sf_file *f;
  6195. if(pfmt==NULL)
  6196. return 0;
  6197. if((f = findfile(sfd)) == 0)
  6198. return -1;
  6199. if(f->filetype == riffwav)
  6200. *pfmt = WAVE;
  6201. else if(f->filetype == wave_ex)
  6202. *pfmt = WAVE_EX;
  6203. else if(f->filetype== eaaiff)
  6204. *pfmt = AIFF;
  6205. else if(f->filetype ==aiffc)
  6206. *pfmt = AIFC;
  6207. #ifdef ENABLE_PVX
  6208. else if(f->filetype == pvxfile)
  6209. *pfmt = PVOCEX;
  6210. #endif
  6211. else
  6212. return -1;
  6213. return 0;
  6214. }
  6215. int sfgetchanmask(int sfd)
  6216. {
  6217. struct sf_file *f;
  6218. //int mask = 0; //default is generic (unassigned)
  6219. if((f = findfile(sfd)) ==NULL)
  6220. return -1;
  6221. if(f->filetype==wave_ex)
  6222. return f->fmtchunkEx.dwChannelMask;
  6223. return 0;
  6224. }
  6225. //private, but used by sndsystem
  6226. int _rsf_getbitmask(int sfd)
  6227. {
  6228. struct sf_file *f;
  6229. if((f = findfile(sfd)) ==NULL)
  6230. return 0;
  6231. return f->bitmask;
  6232. }
  6233. int sf_getchanformat(int sfd, channelformat *chformat)
  6234. {
  6235. struct sf_file *f;
  6236. if((f = findfile(sfd)) ==NULL)
  6237. return -1;
  6238. if(chformat==NULL)
  6239. return -1;
  6240. *chformat = f->chformat;
  6241. return 0;
  6242. }
  6243. const char* sf_getfilename(int sfd)
  6244. {
  6245. struct sf_file *f;
  6246. if((f = findfile(sfd)) ==NULL)
  6247. return NULL;
  6248. return (const char *) f->filename;
  6249. }
  6250. int sf_getcontainersize(int sfd)
  6251. {
  6252. struct sf_file *f;
  6253. if((f = findfile(sfd)) ==NULL)
  6254. return -1;
  6255. return (int) f->fmtchunkEx.Format.wBitsPerSample;
  6256. }
  6257. int sf_getvalidbits(int sfd)
  6258. {
  6259. struct sf_file *f;
  6260. if((f = findfile(sfd)) ==NULL)
  6261. return -1;
  6262. return (int) f->fmtchunkEx.Samples.wValidBitsPerSample;
  6263. }
  6264. //keep this as private func for now, but used by snd routines
  6265. // may have pos >2GB so need unsigned retval
  6266. unsigned int _rsf_getmaxpeak(int sfd,float *peak)
  6267. {
  6268. struct sf_file *f;
  6269. int i;
  6270. double peakval = 0.0;
  6271. if((f = findfile(sfd)) ==NULL)
  6272. return 0xFFFFFFFF;
  6273. if(f->peaks == NULL)
  6274. return 0;
  6275. for(i=0; i < f->fmtchunkEx.Format.nChannels; i++)
  6276. peakval = max(peakval,(double)(f->peaks[i].value));
  6277. *peak = (float) peakval;
  6278. return 1;
  6279. }
  6280. int addprop(struct sf_file *f, char *propname, char *src, int size)
  6281. {
  6282. struct property /* *pp,*/ **ppp;
  6283. /*char *np;*/
  6284. if(f->curpropsize + (signed int)strlen(propname) + 2 + 2*size > f->proplim) {
  6285. rsferrno = ESFNOSPACE;
  6286. rsferrstr = "No space in extended properties for new property data";
  6287. return -1;
  6288. }
  6289. for(ppp = &f->props; *ppp != 0; ppp = &(*ppp)->next)
  6290. ;
  6291. if((*ppp = ALLOC(struct property)) == 0
  6292. ||((*ppp)->name = (char *) malloc(strlen(propname)+1)) == 0
  6293. ||((*ppp)->data = (char *) malloc(size)) == 0) {
  6294. rsferrno = ESFNOMEM;
  6295. rsferrstr = "No memory for bigger property data";
  6296. return -1;
  6297. }
  6298. strcpy((*ppp)->name, propname);
  6299. memcpy((*ppp)->data, src, size);
  6300. (*ppp)->size = size;
  6301. (*ppp)->next = 0;
  6302. f->curpropsize += strlen(propname) + 2 + 2*size;
  6303. f->propschanged = 1;
  6304. return 0;
  6305. }
  6306. #ifdef ENABLE_PVX
  6307. //pvxprops to sfsys props
  6308. static int writefirstprop(struct sf_file *f, char *propname, char *src, int size)
  6309. {
  6310. struct property /* *pp,*/ **ppp;
  6311. ppp = &f->props;
  6312. if((*ppp = ALLOC(struct property)) == 0
  6313. ||((*ppp)->name = (char *) malloc(strlen(propname)+1)) == 0
  6314. ||((*ppp)->data = (char *) malloc(size)) == 0) {
  6315. rsferrno = ESFNOMEM;
  6316. rsferrstr = "No memory for bigger property data";
  6317. return -1;
  6318. }
  6319. strcpy((*ppp)->name, propname);
  6320. memcpy((*ppp)->data, src, size);
  6321. (*ppp)->size = size;
  6322. (*ppp)->next = 0;
  6323. f->curpropsize += strlen(propname) + 2 + 2*size;
  6324. f->proplim = 1000; // RWD completely arbitrary!
  6325. // f->propschanged = 1; // because this is a quasi-creation of ana file
  6326. return 0;
  6327. }
  6328. #endif
  6329. /* required mapping:
  6330. PVX ----------> ANA
  6331. nAnalysisBins N... *2 = props.chans
  6332. overlap decfac
  6333. format=PVOC_AMP_FREQ [no field - always this format, have to reject other type of pvx file]
  6334. srate origrate
  6335. arate arate AND (int) WAV srate
  6336. */
  6337. #ifdef ENABLE_PVX
  6338. /* may as well set all props here, including basic ones from WAVFORMATEX */
  6339. static int pvx_createprops(struct sf_file *f) {
  6340. struct property **ppp = &f->props;
  6341. sampletype samptype;
  6342. unsigned int origsize, origrate, winlen,decfac,analchans;
  6343. float arate;
  6344. #ifdef _DEBUG
  6345. assert(f->curpropsize ==0);
  6346. assert(f->pvxprops != NULL);
  6347. /* NB oddity of CDP ana format - sets WAV sample rate as (int) analysis rate,
  6348. as shown by dirsf */
  6349. // assert(f->fmtchunkEx.Format.nSamplesPerSec == 0);
  6350. #endif
  6351. /* map pvx props to .ana props - not all are identical */
  6352. if(f->pvxprops->wSourceFormat==WAVE_FORMAT_IEEE_FLOAT)
  6353. samptype = FLOAT32;
  6354. else {
  6355. switch(f->fmtchunkEx.Format.wBitsPerSample){
  6356. case 24:
  6357. samptype = INT2424; /* can't represent INT2432 in anaprops) */
  6358. break;
  6359. case 32:
  6360. samptype = INT_32;
  6361. break;
  6362. default:
  6363. samptype = SHORT16;
  6364. break;
  6365. }
  6366. }
  6367. /* next, we have to convert Format into apparent floatsam file...*/
  6368. analchans = f->pvxprops->nAnalysisBins * 2;
  6369. origsize = (unsigned int) samptype;
  6370. origrate = f->fmtchunkEx.Format.nSamplesPerSec;
  6371. decfac = f->pvxprops->dwWinlen;
  6372. arate = f->pvxprops->fAnalysisRate;
  6373. winlen = f->pvxprops->dwWinlen;
  6374. decfac = f->pvxprops->dwOverlap;
  6375. /* set all WAV fornat fields as an .ana file would do... */
  6376. // TODO: allocate and populate char* memory block for proerties, as if getting props block from file
  6377. // call parseprops to load into f->props
  6378. // have to make first prop entry explicitly, then can call addprop for the rest
  6379. if(writefirstprop(f,"original sampsize",(char*) & origsize, sizeof(int)) < 0) {
  6380. rsferrstr = "Failure to write original sample size";
  6381. return -1;
  6382. }
  6383. if(addprop(f,"original sample rate",(char *)&origrate,sizeof(int))<0){
  6384. rsferrstr = "Failure to write original sample rate";
  6385. return -1;
  6386. }
  6387. if(addprop(f,"arate",(char *) &arate,sizeof(float)) < 0){
  6388. rsferrstr = "Failure to write analysis sample rate";
  6389. return -1;
  6390. }
  6391. if(addprop(f,"analwinlen",(char *)& winlen,sizeof(int)) < 0){
  6392. rsferrstr = "Failure to write analysis window length";
  6393. return -1;
  6394. }
  6395. if(addprop(f,"decfactor",(char *)& decfac,sizeof(int)) < 0){
  6396. rsferrstr = "Failure to write decimation factor";
  6397. return -1;
  6398. }
  6399. #ifdef _DEBUG
  6400. // fprintf(stderr, "added all ana properties OK\n");
  6401. #endif
  6402. f->propschanged = 0; // see above: first creation of quasi-ana data
  6403. return 0;
  6404. }
  6405. #endif
  6406. // not used yet...
  6407. #ifdef ENABLE_PVX
  6408. static int sfprops2pvx(struct sf_file *f)
  6409. {
  6410. struct property **ppp = &f->props;
  6411. sampletype samptype;
  6412. unsigned int origsize, origrate, winlen,decfac,analchans;
  6413. float arate;
  6414. #ifdef _DEBUG
  6415. assert(f->curpropsize != 0);
  6416. assert(f->pvxprops != NULL);
  6417. assert(f->pvxfileno >=0);
  6418. #endif
  6419. return 0;
  6420. }
  6421. #endif
  6422. int sf_makepath(char path[], const char* sfname)
  6423. {
  6424. char* fullname = mksfpath(sfname);
  6425. if(fullname==NULL)
  6426. return -1;
  6427. strcpy(path,fullname);
  6428. return 0;
  6429. }