sfsys.c 240 KB

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