| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083 |
- /* RWD version 2022 to support PVOCEX format for Release 8*/
- /*
- * Copyright (c) 1983-2013 Martin Atkins, Richard Dobson and Composers Desktop Project Ltd
- * http://www.rwdobson.com
- * http://www.composersdesktop.com
- *
- This file is part of the CDP System.
- The CDP System is free software; you can redistribute it
- and/or modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
- The CDP System is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with the CDP System; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
- 02111-1307 USA
- *
- */
- /* sfsys 64bit (sfsys2010): handle files up to 4GB : fpos_t/fread/POS64 version */
- /* PC requires FILE64_WIN defined at compiler level */
- /*
- * portable sfsys replacement
- */
- /*RWD.6.5.99 test version for PEAK chunk, etc...
- *RWD.7.99 delete created file on error in format, etc
- *RWD Jan 2004: fixed WAVE_EX GUID reading on big-endian
- */
- /* Nov 2005: allow any channel count for B-Format files */
- /* April 2006: correct bug recoignising .ambi extension in gettypefrom name98() */
- /* but we don't really need to preserve this anyway...could just remove */
- /*April 2006: revise rdwavhdr to scan all chunks, so can pick up PEAK chunk after data chunk,
- as done by SoundForge! */
- /* Oct 2006: changed defs of WORD and DWORD to unsigned, can we support 4GB files???? */
- /* RWD 2009: first version of 64bit file handling for 4GB files.*/
- /* RWD May 2011: hacked rdwavhdr to accept dastardly Wavelab files with 20byte fmt chunk */
- /* PS: and also even more dastardly PT plain wave files with 40byte fmt chunk! */
- /* RWD Jan 2013 fixed bug in getsfsysadtl, return correct padded size */
- /* RWD Nov 2013 RELEASE 7: added MC_SURR_6_1 */
- /* still TODO: replace tmpnam with mkstemp for CDP temporary files for GUI progs (see below)
- * Or: leave it to the GUI progs to sort out! */
- /* RWD Feb 2014: converted to ints for x64 building */
- /* RWD MAR 2015 finished (?) adoption of default value for CDP_SOUND_EXT, eliminated various compiler warnings */
- #ifdef __GNUC__
- # if (defined(__LP64__) || defined(_LP64))
- # define CDPLONG64
- # endif
- #endif
- #ifdef CDPLONG64
- # define CDPLONG int
- #else
- # define CDPLONG long
- #endif
- //static char *rcsid = "$Id: sfsys.c%v 4.0 1998/17/02 00:47:05 martin Exp $";
- /*pstring for AIFC - includes the pad byte*/
- static const char aifc_floatstring[10] = { 0x08,'F','l','o','a','t',0x20,'3','2',0x00};
- static const char aifc_notcompressed[16] = {0x0e,'n','o','t',0x20,'c','o','m','p','r','e','s','s','e','d',0x00};
- /*
- * global state
- */
- int _sfverno = 0x801; //RWD: remember to update this!
- /* NB: private flag! */
- #define SFILE_ANAL (3) /* RWD Nov 2009: no PEAK,CLUE chunk for analysis files */
- #ifdef DEBUG_MAC
- #include <errno.h>
- static void parse_errno(int err)
- {
- switch(err){
- case(EBADF):
- printf("fd is not valid descriptor\n");
- break;
- case(EINVAL):
- printf("fd is socket, not a file\n");
- printf("or: file not open for writing\n");
- break;
- default:
- printf("unrecognised value for err: %d\n",err);
- break;
- }
- }
- #endif
- /*
- * $Log: sfsys.c%v $
- * Revision 2.2 1994/12/13 00:47:05 martin
- * Add declaration for Unix
- *
- * Revision 2.1 1994/10/31 15:49:10 martin
- * New version number to differentiate from versions already shipped
- *
- * Revision 1.1 1994/10/31 15:41:38 martin
- * Initial revision
- *
- */
- /* RWD July 1997: Revision 2.3: add support for new WAV float format
- RWD OCT 97: IMPORTANT FIX: DEAL WITH EXTRA 2 BYTES IN NEW WAVEFORMATEX CHUNK
- We MUST READ wave files correctly; it is not wrong, as such, to continue to write them
- the old way, (at least, for straight PCM format), but it is nevertheless inconsistent
- with modern practice.
- also: completed support for 8bit infiles (read,seek,dirsf)
- added initial support of minimal 'fact' chunk in WAVE files for non-PCM formats
- to use: #define CDP97
- to use Win32 file functions, define CDP99
- */
- #include <stdio.h>
- #ifdef unix
- #include <unistd.h>
- # ifdef __MAC__
- # include <sys/syslimits.h>
- # endif
- #endif
- #include <stdlib.h>
- #include <math.h>
- #include <string.h>
- #include <stdint.h>
- #ifdef _WIN32
- #include <windows.h>
- #include <mmreg.h>
- #endif
- #include <fcntl.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #if defined(_WIN32) || defined(__SC__) || defined (__GNUWIN32__)
- #include <io.h>
- //extern char* _fullpath (char*, const char*, size_t);
- #endif
- #include <errno.h>
- #include <stdio.h>
- #include <time.h>
- #ifdef _DEBUG
- #include <assert.h>
- #endif
- #include <sfsys.h> /*RWD: don't want local copies of this!*/
- /*RWD April 2005 */
- #include "sffuncs.h"
- #include "osbind.h"
- #ifdef _WIN32
- #include "alias.h"
- #endif
- int CDP_COM_READY = 0; /*global flag, ah well...(define in alias.h will access func??)*/
- /* RWD see line ~431; this is basically a mess; difficult to manage order of includes etc in WIN32 - blame windows.h! */
- #ifdef unix
- # ifdef ENABLE_PVX
- # include "pvfileio.h"
- # endif
- #endif
- #include "chanmask.h"
- /* RWD oct 2022 to eliminate pointer aliasing in AIFF srate handling */
- #include "ieee80.h"
- //static char *sfsys_h_rcsid = SFSYS_H_RCSID;
- /*
- * The portability definitions come first
- */
- #ifdef unix
- #define _O_BINARY (0)
- #define _O_RDWR O_RDWR
- #define _O_RDONLY O_RDONLY
- #define _O_CREAT O_CREAT
- #define _O_TRUNC O_TRUNC
- #define _O_EXCL O_EXCL
- #define _S_IWRITE S_IWRITE
- #define _S_IREAD S_IREAD
- #define chsize ftruncate
- #endif
- #if !defined(_WIN32) && !defined(__GNUC__)
- #define __inline /**/
- #endif
- #if defined __MAC__
- #define _MAX_PATH (PATH_MAX)
- #endif
- #if defined MAC || defined __MAC__ || defined linux
- int getAliasName(char *filename,char *newpath)
- {
- return 1;
- }
- #endif
- #ifndef min
- #define min(a,b) (((a) < (b)) ? (a) : (b) )
- #endif
- typedef unsigned short WORD;
- #if defined CDPLONG64 || defined unix
- typedef unsigned int DWORD;
- #else
- /* WIN32, so 4 bytes anyway */
- typedef unsigned long DWORD;
- #endif
- #ifdef NOTDEF
- // moved to sffuncs.h
- # define MSBFIRST (1)
- # define LSBFIRST (1)
- /*RWD May 2007: revise defines to recognise both forms of MAC (__PPC__) */
- # if defined(__I86__) || defined(_X86_) || defined(__i386__) || defined(__i486__) || defined(_IBMR2) || defined(__LITTLE_ENDIAN__)
- # undef MSBFIRST
- # elif defined(M68000) || defined(__sgi) || defined (__ppc__) || defined(__BIG_ENDIAN__)
- # undef LSBFIRST
- # else
- # error "Unknown byte order for this processor"
- # endif
- #if defined(MSBFIRST) && defined(LSBFIRST)
- #error "Internal: can't be both MSB and LSB"
- #endif
- #define REVDWBYTES(t) ( (((t)&0xff) << 24) | (((t)&0xff00) << 8) | (((t)&0xff0000) >> 8) | (((t)>>24) & 0xff) )
- #define REVWBYTES(t) ( (((t)&0xff) << 8) | (((t)>>8) &0xff) )
- /*RWD.6.99 REV3BYTES is a function*/
- static char * REV3BYTES(char *samp_24);
- extern int sampsize[];
- #ifdef MSBFIRST
- #define REVDATAINFILE(f) ((f)->filetype == riffwav || (f)->filetype == wave_ex)
- #else
- #define REVDATAINFILE(f) (((f)->filetype == eaaiff) || ((f)->filetype==aiffc))
- #endif
- #endif
- /*
- * Sfsys-related definitions
- */
- #define SFDBASE (1000)
- #define ALLOC(s) ((s *)malloc(sizeof(s)))
- #define TAG(a,b,c,d) ( ((a)<<24) | ((b)<<16) | ((c)<<8) | (d) )
- /*
- * Wave format-specific stuff
- */
- #ifndef WAVE_FORMAT_PCM
- #define WAVE_FORMAT_PCM (0x0001)
- #endif
- #ifndef WAVE_FORMAT_IEEE_FLOAT
- #define WAVE_FORMAT_IEEE_FLOAT (0x0003)
- #endif
- #ifndef WAVE_FORMAT_EXTENSIBLE
- #define WAVE_FORMAT_EXTENSIBLE (65534)
- #endif
- #define CURRENT_PEAK_VERSION (1)
- #define sizeof_WFMTEX (40)
- #ifdef linux
- #define POS64(x) (x.__pos)
- #else
- #define POS64(x) (x)
- #endif
- typedef union {
- DWORD lsamp;
- float fsamp;
- unsigned char bytes[4];
- } SND_SAMP;
- struct fmtchunk {
- WORD formattag;
- WORD channels;
- DWORD samplespersec;
- DWORD avgbytespersec;
- WORD blockalign;
- };
- #if 0
- // now use wavdefs.h
- # ifndef _WIN32
- typedef struct _GUID
- {
- DWORD Data1;
- WORD Data2;
- WORD Data3;
- unsigned char Data4[8];
- } GUID;
- typedef struct {
- WORD wFormatTag;
- WORD nChannels;
- DWORD nSamplesPerSec;
- DWORD nAvgBytesPerSec;
- WORD nBlockAlign;
- WORD wBitsPerSample;
- WORD cbSize;
- } WAVEFORMATEX;
- # endif
- #endif
- // RWD TO TEST: on PC/MinGW: this need to be ifndef _WIN32 (or could just be ifndef WAVEFORMATEXTENSIBLE ?)
- #if 0
- typedef struct {
- WAVEFORMATEX Format;
- union {
- WORD wValidBitsPerSample; /* bits of precision */
- WORD wSamplesPerBlock; /* valid if wBitsPerSample==0 */
- WORD wReserved; /* If neither applies, set to */
- /* zero. */
- } Samples;
- DWORD dwChannelMask; /* which channels are */
- /* present in stream */
- GUID SubFormat;
- } WAVEFORMATEXTENSIBLE, *PWAVEFORMATEXTENSIBLE;
- #endif
- const static GUID KSDATAFORMAT_SUBTYPE_PCM = {0x00000001,0x0000,0x0010,
- {0x80,
- 0x00,
- 0x00,
- 0xaa,
- 0x00,
- 0x38,
- 0x9b,
- 0x71}};
- const static GUID KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = {0x00000003,0x0000,0x0010,
- {0x80,
- 0x00,
- 0x00,
- 0xaa,
- 0x00,
- 0x38,
- 0x9b,
- 0x71}};
- //B-FORMAT!
- // {00000001-0721-11d3-8644-C8C1CA000000}
- static const GUID SUBTYPE_AMBISONIC_B_FORMAT_PCM = { 0x00000001, 0x0721, 0x11d3,
- { 0x86,
- 0x44,
- 0xc8,
- 0xc1,
- 0xca,
- 0x0,
- 0x0,
- 0x0 } };
- static const GUID SUBTYPE_AMBISONIC_B_FORMAT_IEEE_FLOAT = { 0x00000003, 0x0721, 0x11d3,
- { 0x86,
- 0x44,
- 0xc8,
- 0xc1,
- 0xca,
- 0x0,
- 0x0,
- 0x0 } };
- struct cuepoint {
- DWORD name;
- DWORD position;
- DWORD incchunkid;
- DWORD chunkoffset;
- DWORD blockstart;
- DWORD sampleoffset;
- };
- /*
- * aiff format-specific stuff
- */
- struct aiffchunk {
- DWORD tag;
- DWORD size;
- fpos_t offset;
- char *buf;
- struct aiffchunk *next;
- };
- /*
- * Property storage structures
- */
- #define PROPCNKSIZE (2000)
- struct property {
- char *name;
- char *data;
- int size;
- struct property *next;
- };
- /*
- * Common declarations
- */
- enum sndfiletype {
- unknown_wave,
- riffwav,
- eaaiff,
- aiffc, //RWD sfsys98
- wave_ex, //RWD.5.99
- #ifdef ENABLE_PVX
- pvxfile,
- #endif
- cdpfile //RWD sfsys98
- };
- #ifdef ENABLE_PVX
- # include "pvfileio.h"
- #endif
- //RWD.6.99 NOTE: because of the slight possibility of 32bit int formats, from both file formats,
- // we need an explicit indicator of sample type. We choose to use the fmtchunk.formattag WAVE-style
- //for this, even for AIFF formats. Eventually, AIF-C will be used for all float AIFF files
- struct sf_file {
- char *filename;
- enum sndfiletype filetype;
- int refcnt;
- #if defined _WIN32
- HANDLE fileno;
- #else
- FILE* fileno;
- #endif
- int infochanged;
- int todelete;
- int readonly;
- DWORD mainchunksize;
- fpos_t fmtchunkoffset;
- WAVEFORMATEXTENSIBLE fmtchunkEx; //RWD NB: (for pvocex) includes WAVEFORMATEX as 'Format'
- int bitmask;
- fpos_t datachunkoffset;
- /* typedef from long long */
- __int64 datachunksize;
- __int64 sizerequested;
- int extrachunksizes;
- struct aiffchunk *aiffchunks;
- int proplim;
- fpos_t propoffset;
- int propschanged;
- int curpropsize;
- struct property *props;
- #ifdef ENABLE_PVX
- PVOCDATA *pvxprops;
- int pvxfileno;
- #endif
- DWORD curpos;
- fpos_t factchunkoffset;
- int header_set; //streaming: disallow header updates
- int is_shortcut;
- //RWD.6.5.99
- time_t peaktime;
- fpos_t peakchunkoffset;
- CHPEAK *peaks;
- channelformat chformat;
- int min_header;
- };
- /*
- * for later!!
- * I think all we have to do is keep an fd open for each file open, and share
- * the other information - we don't have to worry about being thread-safe, etc!!!
- */
- struct sf_openfile {
- struct sf_file *file;
- #if defined _WIN32
- HANDLE fileno;
- #else
- FILE* fileno;
- #endif
- DWORD curpos;
- };
- /*
- * Values for sizerequested
- */
- #define ES_EXIST (-2)
- #define LEAVESPACE (10*1024) /* file space that must be left */ //RWD? align to cluster size?
- /*
- * internal state
- */
- int rsferrno = 0;
- char *rsferrstr = "no previous error";
- static struct sf_file *findfile(int sfd);
- static struct sf_file *sf_files[SF_MAXFILES];
- //static enum sndfiletype gettypefromname(const char *path); //RWD98: lets declare this here
- static enum sndfiletype gettypefromname98(const char *path);
- static enum sndfiletype gettypefromfile(struct sf_file *f);
- static int wrwavhdr98(struct sf_file *f, int channels, int srate, int stype);
- static int wraiffhdr98(struct sf_file *f, int channels, int srate, int stype);
- static int wavupdate98(time_t thistime,struct sf_file *f);
- static int aiffupdate(time_t thistime,struct sf_file *f);
- static int aiffupdate98(time_t thistime,struct sf_file *f);
- //private, but used by snd routines
- unsigned int _rsf_getmaxpeak(int sfd,float *peak);
- /*RWD 3:2000 to add analysis properties internally */
- static int addprop(struct sf_file *f, char *propname, char *src, int size);
- #ifdef ENABLE_PVX
- static int writefirstprop(struct sf_file *f, char *propname, char *src, int size);
- static int pvx_createprops(struct sf_file *f);
- #endif
- static int compare_guids(const GUID *gleft, const GUID *gright)
- {
- const char *left = (const char *) gleft, *right = (const char *) gright;
- return !memcmp(left,right,sizeof(GUID));
- }
- static int file_exists(const char * fname);
- static int check_guid(struct sf_file *f)
- {
- //expects a GUID to be loaded already,
- //at present, we only need to know if this is b-format or not.
- //but might as well validate floatsam format against nBits , jic
- if(f->filetype != wave_ex) //should be an assert, but this is NOT a console lib!
- return 1;
- f->chformat = MC_STD;
- //we elabotate on possible std assignments later...
- if(compare_guids(&(f->fmtchunkEx.SubFormat),&(KSDATAFORMAT_SUBTYPE_PCM)))
- return 0;
-
- if(compare_guids(&(f->fmtchunkEx.SubFormat),&(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
- if(f->fmtchunkEx.Format.wBitsPerSample == 32)
- return 0;
-
- if(compare_guids(&(f->fmtchunkEx.SubFormat),&(SUBTYPE_AMBISONIC_B_FORMAT_PCM))) {
- f->chformat = MC_BFMT;
- return 0;
- }
-
- if(compare_guids(&(f->fmtchunkEx.SubFormat),&(SUBTYPE_AMBISONIC_B_FORMAT_IEEE_FLOAT))) {
- if(f->fmtchunkEx.Format.wBitsPerSample == 32){
- f->chformat = MC_BFMT;
- return 0;
- }
- }
-
- return 1;
- }
- /* RWD note: if not Windows, we use std C ftruncate() */
- #if defined _WIN32
- static int w_ch_size(HANDLE fh,__int64 size)
- {
- //#ifdef FILE64_WIN
- LARGE_INTEGER li;
- li.QuadPart = size;
- li.LowPart = SetFilePointer(fh,li.LowPart,&li.HighPart,FILE_BEGIN);
- if(li.LowPart != 0xFFFFFFFF && GetLastError() == NO_ERROR){
- if (!SetEndOfFile(fh))
- return -1;
- }
- else
- return -1;
- // #else
- // if(SetFilePointer(fh,(long) size,NULL,FILE_BEGIN)== 0xFFFFFFFF
- // || !SetEndOfFile(fh))
- // return -1;
- // #endif
- return 0;
- }
- #endif
- /*
- * read/write routines
- */
- /* RWD 2007 executive decision not to allow cnt >= 2GB! */
- #if defined _WIN32
- static __inline int
- doread(struct sf_file *f, char *buf, int cnt)
- {
- DWORD done = 0, count = (DWORD) cnt;
- if(f->fileno == INVALID_HANDLE_VALUE)
- return 1;
- if(!ReadFile(f->fileno, buf, count,&done,NULL)){
- # ifdef _DEBUG
- LPVOID lpMsgBuf;
- FormatMessage(
- FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
- NULL,
- GetLastError(),
- MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
- (LPTSTR) &lpMsgBuf,
- 0,
- NULL
- );
- # ifndef WINDOWS
- fprintf(stderr,(const char *)lpMsgBuf);
- # else
- MessageBox( NULL, lpMsgBuf, "GetLastError", MB_OK|MB_ICONINFORMATION );
- # endif
- LocalFree( lpMsgBuf );
- # endif
- return 1;
- }
- return done != count;
- }
- #else
- //RWD NB returns ERROR if requested byte-count not read
- static __inline int
- doread(struct sf_file *f, char *buf, int cnt)
- {
- int done = fread(buf,sizeof(char),cnt,f->fileno);
- return done != cnt;
- }
- #endif
- /* RWD 31/11/23 : ~msf funcs used to read char strings (TAG name in Aiff/WAVE), lsf to read numbers */
- static int
- read_w_lsf(WORD *wp, struct sf_file *f)
- {
- WORD w;
- if(doread(f, (char *)&w, sizeof(WORD)))
- return 1;
- //#ifdef MSBFIRST
- // *wp = REVWBYTES(w);
- //#else
- *wp = w;
- //#endif
- return 0;
- }
- static int
- read_w_msf(WORD *wp, struct sf_file *f)
- {
- WORD w;
- if(doread(f, (char *)&w, sizeof(WORD)))
- return 1;
- //#ifdef LSBFIRST
- *wp = REVWBYTES(w);
- //#else
- // *wp = w;
- //#endif
- return 0;
- }
- static int
- read_dw_lsf(DWORD *dwp, struct sf_file *f)
- {
- DWORD dw;
- if(doread(f, (char *)&dw, sizeof(DWORD)))
- return 1;
- //#ifdef MSBFIRST
- // *dwp = REVDWBYTES(dw);
- //#else
- *dwp = dw;
- //#endif
- return 0;
- }
- static int
- read_dw_msf(DWORD *dwp, struct sf_file *f)
- {
- DWORD dw;
- if(doread(f, (char *)&dw, sizeof(DWORD)))
- return 1;
- //#ifdef LSBFIRST
- *dwp = REVDWBYTES(dw);
- //#else
- // *dwp = dw;
- //#endif
- return 0;
- }
- #if defined _WIN32
- static __inline int
- dowrite(struct sf_file *f, char *buf, int cnt)
- {
- DWORD done = 0, count = (DWORD)cnt;
- if(!WriteFile(f->fileno, buf, count,&done,NULL))
- return 1;
- return done != count;
- }
- #else
- static __inline int
- dowrite(struct sf_file *f, char *buf, int cnt)
- {
- int done = fwrite(buf,sizeof(char),cnt,f->fileno);
- return done != cnt;
- }
- #endif
- static int
- write_w_lsf(WORD w, struct sf_file *f)
- {
- //#ifdef MSBFIRST
- // w = REVWBYTES(w);
- //#endif
- return dowrite(f, (char *)&w, sizeof(WORD));
- }
- static int
- write_w_msf(WORD w, struct sf_file *f)
- {
- //#ifdef LSBFIRST
- w = REVWBYTES(w);
- //#endif
- return dowrite(f, (char *)&w, sizeof(WORD));
- }
- static int
- write_dw_lsf(DWORD dw, struct sf_file *f)
- {
- //#ifdef MSBFIRST
- // dw = REVDWBYTES(dw);
- //#endif
- return dowrite(f, (char *)&dw, sizeof(DWORD));
- }
- static int
- write_dw_msf(DWORD dw, struct sf_file *f)
- {
- //#ifdef LSBFIRST
- dw = REVDWBYTES(dw);
- //#endif
- return dowrite(f, (char *)&dw, sizeof(DWORD));
- }
- //RWD.6.5.99 write peak data
- /* NB position values are of frames, so int good for 2GB anyway */
- static int write_peak_lsf(int channels, struct sf_file *f)
- {
- int i;
- DWORD peak[2];
- SND_SAMP ssamp;
-
- #ifdef _DEBUG
- if(f->peaks==NULL){
- printf("\nerror: attempt to write uninitialized peak data");
- return 1;
- }
- #endif
- for(i=0; i < channels; i++){
- // /*long*/ DWORD *pdw;
- // pdw = (/*long*/DWORD *) &(f->peaks[i].value); /* RWD replaced with union */
- ssamp.fsamp = f->peaks[i].value;
- //peak[0] = *pdw;
- peak[0] = ssamp.lsamp;
- peak[1] = f->peaks[i].position;
- //#ifdef MSBFIRST
- // peak[0] = REVDWBYTES(peak[0]);
- // peak[1] = REVDWBYTES(peak[1]);
- //#endif
- if(dowrite(f,(char *) peak, 2 * sizeof(DWORD)))
- return 1;
- }
- return 0;
- }
- static int read_peak_lsf(int channels, struct sf_file *f)
- {
- int i;
- DWORD peak[2];
- SND_SAMP ssamp;
- #ifdef _DEBUG
- if(f->peaks==NULL){
- printf("\nerror: attempt to write uninitialized peak data");
- return 1;
- }
- #endif
- for(i=0;i < channels; i++){
- if(doread(f,(char *)peak,2 * sizeof(DWORD)))
- return 1;
- //#ifdef MSBFIRST
- // peak[0] = REVDWBYTES(peak[0]);
- // peak[1] = REVDWBYTES(peak[1]);
- //#endif
- ssamp.lsamp = peak[0];
- //f->peaks[i].value = *(float *) &(peak[0]); /* RWD TODO: replaced with union */
- f->peaks[i].value = ssamp.fsamp;
- f->peaks[i].position = peak[1];
- }
- return 0;
- }
- static int write_peak_msf(int channels, struct sf_file *f)
- {
- int i;
- DWORD peak[2];
- SND_SAMP ssamp;
- for(i=0; i < channels; i++){
- // /*long*/DWORD *pdw;
- //pdw = (/*long*/DWORD *) &(f->peaks[i].value); /* RWD replaced with union */
- ssamp.fsamp = f->peaks[i].value;
- // peak[0] = *pdw;
- peak[0] = ssamp.lsamp;
- peak[1] = f->peaks[i].position;
- //#ifdef LSBFIRST
- peak[0] = REVDWBYTES(peak[0]);
- peak[1] = REVDWBYTES(peak[1]);
- //#endif
- if(dowrite(f,(char *) peak, 2 * sizeof(DWORD)))
- return 1;
-
- }
- return 0;
-
- }
- static int read_peak_msf(int channels, struct sf_file *f)
- {
- int i;
- DWORD peak[2];
- SND_SAMP ssamp;
- for(i=0;i < channels; i++){
- if(doread(f,(char *)peak,2 * sizeof(DWORD)))
- return 1;
- //#ifdef LSBFIRST
- peak[0] = REVDWBYTES(peak[0]);
- peak[1] = REVDWBYTES(peak[1]);
- //#endif
- ssamp.lsamp = peak[0];
- //f->peaks[i].value = *(float *) &(peak[0]); /* RWD replaced with union */
- f->peaks[i].value = ssamp.fsamp;
- f->peaks[i].position = peak[1];
- }
- return 0;
- }
- /*
- * Fudge Apple extended format, for sample rates
- */
- /* RWD Oct 2022 removed old "TABLE_IEEE754" code */
- /* now using compact Csound code */
- #ifdef DW_EX_OLDCODE
- static int
- read_ex_todw(DWORD *dwp, struct sf_file *f)
- {
- double neg = 1.0;
- WORD exp;
- /*unsigned long*/DWORD ms_sig;
- double res;
- char buf[10]; /* for 80-bit extended float */
- if(doread(f, buf, 10))
- return 1;
- # ifdef LSBFIRST
- exp = REVWBYTES(*(WORD *)&buf[0]);
- ms_sig = (/*unsigned long*/DWORD)REVDWBYTES(*(DWORD *)&buf[2]); /* RWD TODO replace with union */
- # else
- exp = *(WORD *)&buf[0];
- ms_sig = (/*unsigned long*/DWORD)*(DWORD *)&buf[2]; /* RWD TODO replace with union */
- # endif
- if(exp & 0x8000) {
- exp &= ~0x8000;
- neg = -1.0;
- }
- exp -= 16382;
- res = (double)ms_sig/TWOPOW32;
- res = neg*ldexp(res, exp);
- *dwp = (DWORD)(res+0.5);
- return 0;
- }
- static int
- write_dw_toex(DWORD dw, struct sf_file *f)
- {
- double val = (double)dw;
- int neg = 0;
- /*unsigned long*/DWORD mant;
- int exp;
- char buf[10];
-
- if(val < 0.0) {
- val = -val;
- neg++;
- }
- mant = (/*unsigned long*/DWORD)(frexp(val, &exp) * TWOPOW32 + 0.5);
- exp += 16382;
- if(neg)
- exp |= 0x8000;
- # ifdef LSBFIRST
- *(WORD *)&buf[0] = REVWBYTES(exp); /* RWD TODO replace all with union? */
- *(DWORD *)&buf[2] = REVDWBYTES((DWORD)mant);
- # else
- *(WORD *)&buf[0] = exp;
- *(DWORD *)&buf[2] = mant;
- # endif
- *(DWORD *)&buf[6] = 0;
- return dowrite(f, buf, 10);
- }
- #else
- /* use Csound funcs */
- static int
- read_ex_todw(DWORD *dwp, struct sf_file *f)
- {
- double Csound_res = 0.0;
- char buf[10]; /* for 80-bit extended float */
- if(doread(f, buf, 10))
- return 1;
- Csound_res = ieee_80_to_double((unsigned char *) buf);
- *dwp = (DWORD) Csound_res;
- return 0;
- }
- static int
- write_dw_toex(DWORD dw, struct sf_file *f)
- {
- double val = (double)dw;
- char buf[10];
- double_to_ieee_80(val,(unsigned char *) buf);
- return dowrite(f,buf,10);
- }
- #endif // DW_EX_OLDCODE
- /*
- * wave file-format specific routines
- */
- static int
- getsfsyscue(struct sf_file *f)
- {
- DWORD cnt;
- int rc = 0;
- struct cuepoint cue;
-
- if(read_dw_lsf(&cnt, f))
- return -1;
- while(cnt-- > 0) {
- if(read_dw_msf(&cue.name, f)
- ||read_dw_lsf(&cue.position, f)
- ||read_dw_msf(&cue.incchunkid, f)
- ||read_dw_lsf(&cue.chunkoffset, f)
- ||read_dw_lsf(&cue.blockstart, f)
- ||read_dw_lsf(&cue.sampleoffset, f))
- return -1;
- if(cue.name == TAG('s','f','i','f'))
- rc = 1;
- }
- return rc;
- }
- /*
- * extended properties are as follows:
- *
- * property name '\n'
- * property value '\n'
- * ...
- * '\n'
- */
- static int
- xtoi(int ch)
- {
- if(ch >= '0' && ch <= '9')
- return ch - '0';
- if(ch >= 'A' && ch <= 'F')
- return ch - 'A' + 10;
- if(ch >= 'a' && ch <= 'f')
- return ch - 'a' + 10;
- return 0;
- }
- static int
- itox(int i)
- {
- static char trans[] = "0123456789ABCDEF";
- return trans[i&0x0f];
- }
- static void
- parseprops(struct sf_file *f, char *data)
- {
- char *cp = data;
- char *ep, *evp;
- int cnt;
- struct property **ppp = &f->props;
- struct property *np;
- f->curpropsize = 0;
- while(cp-data < f->proplim && *cp != '\n') {
- if((ep = strchr(cp, '\n')) == 0
- ||(evp = strchr(ep+1, '\n')) == 0
- ||((evp-ep-1)&1))
- return;
- if((np = ALLOC(struct property)) == 0
- ||(np->name = (char *) malloc(ep-cp+1)) == 0
- ||(np->data = (char *) malloc((evp-ep-1)/2)) == 0)
- return;
- np->size = (evp-ep-1)/2;
- np->next = 0;
- memcpy(np->name, cp, ep-cp);
- np->name[ep-cp] = '\0';
- for(cnt = 0; cnt < np->size; cnt++)
- np->data[cnt] = (xtoi((ep+1)[2*cnt])<<4) + xtoi((ep+1)[2*cnt+1]);
- *ppp = np;
- ppp = &np->next;
- f->curpropsize += strlen(np->name) + 1 + np->size + 1;
- cp = evp+1;
- }
- }
- static int
- writeprops(struct sf_file *f)
- {
- char *obuf, *op;
- int cnt;
- struct property *p = f->props;
-
- if((obuf = (char *) malloc(f->proplim)) == 0) {
- rsferrno = ESFNOMEM;
- rsferrstr = "No memory to write properties with";
- return -1;
- }
- op = obuf;
-
- while(p != 0) {
- strcpy(op, p->name);
- op += strlen(p->name);
- *op++ = '\n';
- for(cnt = 0; cnt < p->size; cnt++) {
- *op++ = itox(p->data[cnt]>>4);
- *op++ = itox(p->data[cnt]);
- }
- *op++ = '\n';
- if(op-obuf >= f->proplim) //RWD.1.99 this is really an assert test...
- abort();
- p = p->next;
- }
- while(op < &obuf[f->proplim])
- *op++ = '\n';
- /*RWD 2007: we rely on all props being within first 2GB of file! */
- #if defined _WIN32
- if (SetFilePointer(f->fileno,(LONG)f->propoffset,NULL,FILE_BEGIN) == 0xFFFFFFFF
- #else
- if(fseeko(f->fileno, POS64(f->propoffset), SEEK_SET)
- #endif
- ||dowrite(f, obuf, f->proplim)) {
- rsferrno = ESFWRERR;
- rsferrstr = "Write error writing new property values";
- return -1;
- }
- free(obuf);
- return 0;
- }
- static int
- getsfsysadtl(struct sf_file *f, int adtllen)
- {
- DWORD tag, size;
- DWORD name;
- fpos_t bytepos;
- char *propspace;
- char buf[1];
- while(adtllen > 0) {
- if(read_dw_msf(&tag, f)
- ||read_dw_lsf(&size, f))
- return -1;
- switch(tag) {
- case TAG('n','o','t','e'):
- if(read_dw_msf(&name, f))
- return -1;
- if(name != TAG('s','f','i','f')
- ||(int)(POS64(f->propoffset)) >= 0
- ||(propspace = (char *) malloc(size-sizeof(DWORD))) == 0) {
- #if defined _WIN32
- if(SetFilePointer(f->fileno,(LONG)((size-sizeof(DWORD)+1)&~1),NULL,FILE_CURRENT)== 0xFFFFFFFF)
- #else
- if(fseek(f->fileno, (size-sizeof(DWORD)+1)&~1, SEEK_CUR))
- #endif
- return -1;
- break;
- }
- f->proplim = size-sizeof(DWORD);
- #if defined _WIN32
- if((f->propoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF
- ||doread(f, propspace, size-sizeof(DWORD)))
- return -1;
- #else
- if(fgetpos(f->fileno,&bytepos)
- ||doread(f, propspace, size-sizeof(DWORD)))
- return -1;
- f->propoffset = bytepos;
- #endif
- parseprops(f, propspace);
- free(propspace);
- if(size&1)
- doread(f, buf, 1);
- break;
- default:
- #if defined _WIN32
- if(SetFilePointer(f->fileno, (size+1)&~1,NULL,FILE_CURRENT) == 0xFFFFFFFF)
- return -1;
- #else
- if(fseek(f->fileno, (size+1)&~1, SEEK_CUR) < 0)
- return -1;
- #endif
- break;
- }
- adtllen -= 2*sizeof(DWORD) + ((size+1)&~1); /* RWD Jan 2013 */
- }
- return 0;
- }
- //RWD.7.99 TODO: set f->min_header here?
- /*RWD 2007: MUST use DWORD to enure we get sizes up to 4GB */
- /* BUT: if we seek to end of data chunk, need 64bit seek */
- static int
- rdwavhdr(struct sf_file *f)
- {
- DWORD tag, size;
- int fmtseen = 0;
- int dataseen = 0; /*RWD April 2006: try to read PEAK chunk after data (boo hiss Sony! )*/
- int err = 0; /* "" */
- int gotsfsyscue = 0;
- DWORD factsize = 0;
- DWORD peak_version;
- #if defined _WIN32
- LARGE_INTEGER pos64; /* pos64.QuadPart is __int64 */
- #endif
- fpos_t bytepos;
- //WAVEFORMATEXTENSIBLE *pFmtEx;
- if(read_dw_msf(&tag, f)
- ||read_dw_lsf(&size, f)
- ||tag != TAG('R','I','F','F')) {
- rsferrno = ESFNOTFOUND;
- rsferrstr = "File is not a RIFF file";
- return 1;
- }
- if(size < 4) {
- rsferrno = ESFNOTFOUND;
- rsferrstr = "File data size is too small";
- return 1;
- }
- if(read_dw_msf(&tag, f)
- ||tag != TAG('W','A','V','E')) {
- rsferrno = ESFNOTFOUND;
- rsferrstr = "File is not a wave RIFF file";
- return 1;
- }
- f->filetype = riffwav; //might be wave_ex
- f->mainchunksize = size;
- f->extrachunksizes = 0;
- f->proplim = 0;
- f->props = 0;
- POS64(f->propoffset) = (unsigned) -1;
- POS64(f->factchunkoffset) = (unsigned) -1;
- //datachunkoffset now initialized in allocsffile
- //RWD.6.99 do I need to do the AIFF getout for bad sizes here too?
- for(;;) {
- if(read_dw_msf(&tag, f)
- ||read_dw_lsf(&size,f)){
- /*RWD April 2006 TODO: detect EOF! */
- err++;
- goto ioerror;
- }
- switch(tag) {
- case TAG('f','m','t',' '):
- //RWD: must deal with possibility of WAVEFORMATEX extra cbSize word
- #if defined _WIN32
- if((f->fmtchunkoffset = SetFilePointer(f->fileno, 0L,NULL, FILE_CURRENT))== 0xFFFFFFFF
- ||read_w_lsf(&f->fmtchunkEx.Format.wFormatTag, f)
- ||read_w_lsf(&f->fmtchunkEx.Format.nChannels, f)
- ||read_dw_lsf(&f->fmtchunkEx.Format.nSamplesPerSec, f)
- ||read_dw_lsf(&f->fmtchunkEx.Format.nAvgBytesPerSec, f)
- ||read_w_lsf(&f->fmtchunkEx.Format.nBlockAlign, f) ) {
- err++;
- goto ioerror;
- }
- #else
- if(fgetpos(f->fileno, &bytepos)
- ||read_w_lsf(&f->fmtchunkEx.Format.wFormatTag, f)
- ||read_w_lsf(&f->fmtchunkEx.Format.nChannels, f)
- ||read_dw_lsf(&f->fmtchunkEx.Format.nSamplesPerSec, f)
- ||read_dw_lsf(&f->fmtchunkEx.Format.nAvgBytesPerSec, f)
- ||read_w_lsf(&f->fmtchunkEx.Format.nBlockAlign, f) ) {
- err++;
- goto ioerror;
- }
- f->fmtchunkoffset = bytepos;
- #endif
- switch(f->fmtchunkEx.Format.wFormatTag) {
- case WAVE_FORMAT_PCM:
- case WAVE_FORMAT_IEEE_FLOAT: //RWD 07:97
- case WAVE_FORMAT_EXTENSIBLE: //RWD.5.99
- if(read_w_lsf(&f->fmtchunkEx.Format.wBitsPerSample, f)) {
- err++;
- goto ioerror;
- }
- //RWD.6.99 set f->fmtchunkEx.Samples.wValidBitsPerSample to this as default
- // will only be changed by a WAVE_EX header
- f->fmtchunkEx.Samples.wValidBitsPerSample = f->fmtchunkEx.Format.wBitsPerSample;
- //deal with things such as 20bits per sample...
- //this covers standard WAVE, WAVE-EX may adjust again
- if(f->fmtchunkEx.Format.wBitsPerSample !=
- ((f->fmtchunkEx.Format.nBlockAlign / f->fmtchunkEx.Format.nChannels) * 8)){
- //deduce the container size
- f->fmtchunkEx.Format.wBitsPerSample =
- ((f->fmtchunkEx.Format.nBlockAlign / f->fmtchunkEx.Format.nChannels) * 8);
- }
- switch(f->fmtchunkEx.Format.wBitsPerSample) {
- case 32: /* floats or longs*/
- break;
- case(24):
- case 16: /* shorts */
- case 8: /* byte -> short mappping */
- /*RWD 07:97*/ if(!(f->fmtchunkEx.Format.wFormatTag == WAVE_FORMAT_PCM ||
- f->fmtchunkEx.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE)){
- rsferrno = ESFNOTFOUND;
- rsferrstr = "can't open Sfile : Format mismatch";
- return 1;
- }
- break;
- default:
- rsferrno = ESFNOTFOUND;
- rsferrstr = "can't open Sfile - unsupported format";
- return 1;
- }
- //now catch any extra bytes, and parse WAVE_EX if we have it...
- if(size > 16){
- unsigned short cbSize;
- if(read_w_lsf(&cbSize,f))
- goto ioerror;
- /* RWD May 2011. Effing Steinberg Wavelab writes a 20byte fmt chunk! */
- /* Feb 2012: AND Pro Tools writes a 40byte fmt chunk! */
- if(cbSize==0){
- int wordstoskip = (size-18) / sizeof(WORD);
- int skip;
- unsigned short dummy;
- for(skip = 0; skip < wordstoskip; skip++){
- if(read_w_lsf(&dummy,f))
- goto ioerror;
- }
- }
- else{
- if(f->fmtchunkEx.Format.wFormatTag != WAVE_FORMAT_EXTENSIBLE){
- rsferrno = ESFNOTFOUND;
- rsferrstr = "unexpected extra format information - not a wave file";
- return 1;
- }
- if(cbSize != 22){
- rsferrno = ESFNOTFOUND;
- rsferrstr = "unexpected extra format information in WAVE_EX file!";
- return 1;
- }
- f->filetype = wave_ex;
- if(read_w_lsf(&(f->fmtchunkEx.Samples.wValidBitsPerSample),f)
- ||
- read_dw_lsf(&(f->fmtchunkEx.dwChannelMask),f)){
- err++;
- goto ioerror;
- }
- //get the GUID
- if(doread(f,(char *) &(f->fmtchunkEx.SubFormat),sizeof(GUID))) {
- err++;
- goto ioerror;
- }
- #ifdef MSBFIRST
- f->fmtchunkEx.SubFormat.Data1 = REVDWBYTES(f->fmtchunkEx.SubFormat.Data1);
- f->fmtchunkEx.SubFormat.Data2 = REVWBYTES(f->fmtchunkEx.SubFormat.Data2);
- f->fmtchunkEx.SubFormat.Data3 = REVWBYTES(f->fmtchunkEx.SubFormat.Data3);
- #endif
- if(check_guid(f)){
- rsferrno = ESFNOTFOUND;
- rsferrstr = "unrecognized WAV_EX subformat";
- return 1;
- }
- //we don't try to ID the spkr-config here: do that in the sf/snd open fucntions
- }
- }
- break;
- default:
- rsferrno = ESFNOTFOUND;
- rsferrstr = "can't open Sfile - unsupported format";
- return 1;
- }
- //set the bitmask here - covers plain WAVE too
- if(f->fmtchunkEx.Samples.wValidBitsPerSample
- < f->fmtchunkEx.Format.wBitsPerSample){
- int mask = 0xffffffff;
- int shift = 32 - f->fmtchunkEx.Format.wBitsPerSample;
- f->bitmask = mask << (shift + (f->fmtchunkEx.Format.wBitsPerSample
- - f->fmtchunkEx.Samples.wValidBitsPerSample));
- }
- fmtseen++;
- break;
- case TAG('L','I','S','T'):
- if(read_dw_msf(&tag, f))
- goto ioerror;
- switch(tag) {
- case TAG('w','a','v','l'):
- rsferrno = ESFNOTFOUND;
- rsferrstr = "Can't open SFfile - no support for list chunks yet!";
- return 1;
- case TAG('a','d','t','l'):
- if(getsfsysadtl(f, size-sizeof(DWORD)) < 0) {
- err++;
- goto ioerror;
- }
- break;
- default:
- #if defined _WIN32
- if(SetFilePointer(f->fileno, size-sizeof(DWORD),NULL, FILE_CURRENT) == 0xFFFFFFFF)
- #else
- POS64(bytepos) = size-sizeof(DWORD);
- if(fseeko(f->fileno, /*size-sizeof(DWORD)*/POS64(bytepos), SEEK_CUR) < 0)
- #endif
- {
- err++;
- goto ioerror;
- }
- break;
- }
- break;
- //read fact chunk (not needed for std PCM files...but we use it anyway in sfsys97!
- case TAG('f','a','c','t'):
- #if defined _WIN32
- if((f->factchunkoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF)
- #else
- if(fgetpos(f->fileno,&f->factchunkoffset))
- #endif
- {
- err++;
- goto ioerror;
- }
- if(read_dw_lsf(&factsize,f)) {
- err++;
- goto ioerror;
- }
- break; //RWD: need to update extrachunksizes?
- //RWD.5.99 read PEAK chunk
- case TAG('P','E','A','K'):
- f->peaks = (CHPEAK *) calloc(f->fmtchunkEx.Format.nChannels,sizeof(CHPEAK));
- if(f->peaks == NULL){
- rsferrno = ESFNOMEM;
- rsferrstr = "No memory for peak data";
- return 1;
- }
- if(read_dw_lsf(&peak_version,f)) {
- err++;
- goto ioerror;
- }
- switch(peak_version){
- case(CURRENT_PEAK_VERSION):
- if(read_dw_lsf((DWORD*) &(f->peaktime),f)){
- err++;
- goto ioerror;
- }
- /* RWD 2007: PEAK chunk is after data chunk in some naff but otherwise legal files,
- so ordinary lseek no good */
- #if defined _WIN32
- pos64.QuadPart = 0;
- pos64.LowPart = SetFilePointer(f->fileno, 0L, &pos64.HighPart, FILE_CURRENT);
- if(pos64.LowPart == 0xFFFFFFFF && GetLastError() != NO_ERROR){
- err++;
- goto ioerror;
- }
- else {
- /* WAVE and AIFF have to fit inside unsigned int */
- f->peakchunkoffset = (unsigned int) pos64.QuadPart;
- if(read_peak_lsf(f->fmtchunkEx.Format.nChannels,f)) {
- err++;
- goto ioerror;
- }
- }
- #else
- if(fgetpos(f->fileno,&f->peakchunkoffset)
- || read_peak_lsf(f->fmtchunkEx.Format.nChannels,f)) {
- err++;
- goto ioerror;
- }
- #endif
- break;
- default:
- #ifdef _DEBUG
- fprintf(stderr,"\nunknown PEAK version!");
- #endif
- free(f->peaks);
- f->peaks = NULL;
- break;
- }
- break;
- case TAG('d','a','t','a'):
- #if defined _WIN32
- /* datachunk MUST be within 2GB! */
- if((f->datachunkoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF){
- err++;
- goto ioerror;
- }
- f->datachunksize = size;
- if(f->fmtchunkEx.Format.wBitsPerSample == 8)
- f->datachunksize *= 2;
- #else
- if(fgetpos(f->fileno,&f->datachunkoffset) ){
- err++;
- goto ioerror;
- }
- f->datachunksize = size;
- if(f->fmtchunkEx.Format.wBitsPerSample == 8)
- f->datachunksize *= 2;
- #endif
- /* skip over data chunk; to try to read later chunks */
- size = (size+1)&~1;
- #if defined _WIN32
- pos64.QuadPart = (__int64) size;
- pos64.LowPart = SetFilePointer(f->fileno, pos64.LowPart,&pos64.HighPart,FILE_CURRENT);
- if(pos64.LowPart == 0xFFFFFFFF && GetLastError() != NO_ERROR){
- err++;
- goto ioerror;
- }
- #else
- /* expect >2GB data chunk, so must use fseeko etc */
- POS64(bytepos) = POS64(f->datachunkoffset) + size;
- if(fsetpos(f->fileno, &bytepos)) {
- err++;
- goto ioerror;
- }
- #endif
- dataseen++;
- break;
- case TAG('c','u','e',' '):
- if((gotsfsyscue = getsfsyscue(f)) < 0) {
- err++;
- goto ioerror;
- }
- break;
- default:
- size = (size+1)&~1;
- /* we trust that only the data chunk will be huge! */
- #if defined _WIN32
- if(SetFilePointer(f->fileno, size, NULL,FILE_CURRENT) == 0xFFFFFFFF) {
- err++;
- goto ioerror;
- }
- #else
- if(fseek(f->fileno, size, SEEK_CUR) < 0) {
- err++;
- goto ioerror;
- }
- #endif
- f->extrachunksizes += size + 2*sizeof(DWORD); //RWD: anonymous chunks - we will copy these one day...
- break;
- }
- }
- /* NOTREACHED */
- ioerror:
- if(fmtseen && dataseen)
- return 0;
- rsferrno = ESFRDERR;
- rsferrstr = "read error (or file too short) reading wav header";
- return 1;
- }
- /********** SFSYS98 version ****************
- * this RECEIVES format data from calling function,
- * to create the required header
- */
- static int
- wrwavhdr98(struct sf_file *f, int channels, int srate, int stype)
- {
- struct cuepoint cue;
- int extra = 0;
- int wordsize;
- #ifdef linux
- fpos_t bytepos = {0};
- #else
- fpos_t bytepos = 0;
- #endif
- WORD cbSize = 0x0000; //RWD for WAVEFORMATEX, FLOAT FORMAT ONLY
- f->mainchunksize = 0; /* we don't know the full size yet! */
- f->extrachunksizes = 0;
- //we will not use sffuncs for 24bit files!
- if(stype >= SAMP_MASKED){
- rsferrstr = "this verson cannot write files in requested format";
- return 1;
- }
- //wordsize = (stype == SAMP_FLOAT ? sizeof(float) : sizeof(short));
- wordsize = sampsize[stype];
- if(stype== SAMP_FLOAT)
- extra = sizeof(WORD);
- if(write_dw_msf(TAG('R','I','F','F'), f)
- ||write_dw_lsf(0, f)
- ||write_dw_msf(TAG('W','A','V','E'), f))
- goto ioerror;
- f->fmtchunkEx.Format.wFormatTag = stype == SAMP_FLOAT ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM;
- f->fmtchunkEx.Format.nChannels = (unsigned short)channels;
- f->fmtchunkEx.Format.nSamplesPerSec = srate;
- f->fmtchunkEx.Format.nAvgBytesPerSec = wordsize * channels * srate;
- f->fmtchunkEx.Format.nBlockAlign = (unsigned short) ( wordsize * channels);
- //for standard WAVE, we set wBitsPerSample to = validbits
- if(stype==SAMP_2024)
- f->fmtchunkEx.Format.wBitsPerSample = 20;
- else if(stype==SAMP_2432)
- f->fmtchunkEx.Format.wBitsPerSample = 24;
- else
- f->fmtchunkEx.Format.wBitsPerSample = (short)(8 * wordsize);
- //need this for wavupdate98()
- f->fmtchunkEx.Samples.wValidBitsPerSample = f->fmtchunkEx.Format.wBitsPerSample;
- if(write_dw_msf(TAG('f','m','t',' '), f)
- ||write_dw_lsf(16 + extra, f) //RWD CDP97: size = 18 to include cbSize field
- #if defined _WIN32
- ||((f->fmtchunkoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF)
- ||write_w_lsf(f->fmtchunkEx.Format.wFormatTag, f)
- ||write_w_lsf(f->fmtchunkEx.Format.nChannels, f)
- ||write_dw_lsf(f->fmtchunkEx.Format.nSamplesPerSec, f)
- ||write_dw_lsf(f->fmtchunkEx.Format.nAvgBytesPerSec, f)
- ||write_w_lsf(f->fmtchunkEx.Format.nBlockAlign, f)
- ||write_w_lsf(f->fmtchunkEx.Format.wBitsPerSample, f)
- )
- goto ioerror;
- #else
- ||fgetpos(f->fileno,&bytepos)
- ||write_w_lsf(f->fmtchunkEx.Format.wFormatTag, f)
- ||write_w_lsf(f->fmtchunkEx.Format.nChannels, f)
- ||write_dw_lsf(f->fmtchunkEx.Format.nSamplesPerSec, f)
- ||write_dw_lsf(f->fmtchunkEx.Format.nAvgBytesPerSec, f)
- ||write_w_lsf(f->fmtchunkEx.Format.nBlockAlign, f)
- ||write_w_lsf(f->fmtchunkEx.Format.wBitsPerSample, f)
- )
- goto ioerror;
- f->fmtchunkoffset = bytepos;
- #endif
- if(stype == SAMP_FLOAT) {
- if(write_w_lsf(cbSize,f))
- goto ioerror;
- }
- //RWD.6.5.99 ADD the PEAK chunk
- if((f->min_header >= SFILE_PEAKONLY) && f->peaks){
- int i,size;
- DWORD now = 0;
- for(i=0;i < channels; i++){
- f->peaks[i].value = 0.0f;
- f->peaks[i].position = 0;
- }
- size = 2 * sizeof(DWORD) + channels * sizeof(CHPEAK);
- if(write_dw_msf(TAG('P','E','A','K'),f)
- || write_dw_lsf(size,f)
- #if defined _WIN32
- || ((f->peakchunkoffset = SetFilePointer(f->fileno,0L,NULL, FILE_CURRENT))== 0xFFFFFFFF)
- || write_dw_lsf(CURRENT_PEAK_VERSION,f)
- || write_dw_lsf(now,f)
- || write_peak_lsf(channels,f))
- goto ioerror;
- #else
- || fgetpos(f->fileno,&bytepos)
- || write_dw_lsf(CURRENT_PEAK_VERSION,f)
- || write_dw_lsf(now,f)
- || write_peak_lsf(channels,f))
- goto ioerror;
- f->peakchunkoffset = bytepos;
- #endif
- }
- if(f->min_header >= SFILE_CDP){
- /*
- * add the cue point/note chunk for properties
- */
- /* RWD Nov 2009: don't need cue for analysis files */
- if(f->min_header==SFILE_CDP){
- //RWD TODO: add switch to skip writing this extra stuff!
- if(write_dw_msf(TAG('c','u','e',' '), f)
- ||write_dw_lsf(sizeof(struct cuepoint) + sizeof(DWORD), f) )
- goto ioerror;
- cue.name = TAG('s','f','i','f');
- cue.position = 0;
- cue.incchunkid = TAG('d','a','t','a');
- cue.chunkoffset = 0;
- cue.blockstart = 0;
- cue.sampleoffset = 0;
- if(write_dw_lsf(1, f) /* one cue point */
- ||write_dw_msf(cue.name, f)
- ||write_dw_lsf(cue.position, f)
- ||write_dw_msf(cue.incchunkid, f)
- ||write_dw_lsf(cue.chunkoffset, f)
- ||write_dw_lsf(cue.blockstart, f)
- ||write_dw_lsf(cue.sampleoffset, f) )
- goto ioerror;
- }
- /*... add a LIST chunk of type 'adtl'... */
- if(write_dw_msf(TAG('L','I','S','T'), f)
- ||write_dw_lsf(sizeof(DWORD) + 3*sizeof(DWORD) + PROPCNKSIZE, f)
- ||write_dw_msf(TAG('a','d','t','l'), f) )
- goto ioerror;
- /* add the property-space note chunk */
- if(write_dw_msf(TAG('n','o','t','e'), f)
- ||write_dw_lsf(sizeof(DWORD) + PROPCNKSIZE, f)
- ||write_dw_msf(TAG('s','f','i','f'), f)
- #if defined _WIN32
- ||((f->propoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF)
- ||SetFilePointer(f->fileno, (long)PROPCNKSIZE,NULL, FILE_CURRENT) == 0xFFFFFFFF )
- goto ioerror;
- #else
- ||fgetpos(f->fileno, &bytepos)
- ||fseek(f->fileno, (long)PROPCNKSIZE, SEEK_CUR) < 0)
- goto ioerror;
- f->propoffset = bytepos;
- #endif
- f->propschanged = 1;
- f->proplim = PROPCNKSIZE;
- }
- /*
- * and add the data chunk
- */
- f->datachunksize = 0;
- if(write_dw_msf(TAG('d','a','t','a'), f)
- ||write_dw_lsf(0, f)
- #if defined _WIN32
- ||((f->datachunkoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF))
- goto ioerror;
- #else
- ||fgetpos(f->fileno, &bytepos))
- goto ioerror;
- f->datachunkoffset = bytepos;
- #endif
- f->header_set = 1; //later, may allow update prior to first write ?
- return 0;
- /* NOTREACHED */
- ioerror:
- rsferrno = ESFWRERR;
- rsferrstr = "write error writing formatted wav header";
- return 1;
- }
- //wave-ex special
- static int
- wrwavex(struct sf_file *f, SFPROPS *props)
- {
- struct cuepoint cue;
- //int extra = 0;
- int wordsize;
- WORD validbits,cbSize = 22;
- GUID guid;
- GUID *pGuid = NULL;
- //int fmtsize = sizeof_WFMTEX;
- fpos_t bytepos;
- POS64(bytepos) = 0;
-
- f->mainchunksize = 0; /* we don't know the full size yet! */
- f->extrachunksizes = 0;
- POS64(f->propoffset) = 0;
- if(props->chformat==STDWAVE){
- rsferrno = ESFBADPARAM;
- rsferrstr = "std wave format requested for WAVE-EX file!";
- return 1;
- }
-
- if(props->samptype == FLOAT32){
- pGuid = (GUID *) &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
-
- }
- else{
- pGuid =(GUID *) &KSDATAFORMAT_SUBTYPE_PCM;
- }
- //NB AIFF and AIFF-C don't support masked formats - just write the required larger container size
- switch(props->samptype){
- case(INT_32):
- case(FLOAT32):
- case(INT2432):
- wordsize = sizeof(/*long*/int);
- break;
- case(INT2424):
- case(INT2024):
- wordsize = 3;
- break;
- case(SHORT16):
- wordsize= sizeof(short);
- break;
- default:
- //don't accept SHORT8, can't deal with INT_MASKED yet - no info in SFPROPS yet!
- rsferrno = ESFBADPARAM;
- rsferrstr = "unsupported sample format requested for WAVE-EX file";
- return 1;
- }
- if(props->samptype==INT2432)
- validbits = (WORD)24;
- else if(props->samptype==INT2024)
- validbits = (WORD)20;
- else
- validbits = (WORD)( 8 * wordsize); //deal with more masks in due course...
-
- if(write_dw_msf(TAG('R','I','F','F'), f)
- ||write_dw_lsf(0, f)
- ||write_dw_msf(TAG('W','A','V','E'), f))
- goto ioerror;
- /* MC_STD,MC_GENERIC,MC_LCRS,MC_BFMT,MC_DOLBY_5_1,
- MC_SURR_5_0,MC_SURR_7_1,MC_CUBE,MC_WAVE_EX
- */
-
- f->fmtchunkEx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
- f->fmtchunkEx.Format.nChannels = (unsigned short) props->chans;
- f->fmtchunkEx.Format.nSamplesPerSec = props->srate;
- f->fmtchunkEx.Format.nAvgBytesPerSec = wordsize * props->chans * props->srate;
- f->fmtchunkEx.Format.nBlockAlign = (unsigned short) ( wordsize * props->chans);
- f->fmtchunkEx.Format.wBitsPerSample = (WORD)(wordsize * 8);
- f->fmtchunkEx.Samples.wValidBitsPerSample = validbits;
- /*RWD Jan 30 2007: permit mask bits < nChans */
- switch(props->chformat){
- case(MC_STD):
- f->fmtchunkEx.dwChannelMask = SPKRS_UNASSIGNED;
- break;
- case(MC_MONO):
- if(props->chans /*!=*/ < 1){ /*RWD Jan 30 2007 */
- rsferrno = ESFBADPARAM;
- rsferrstr = "conflicting channel configuration for WAVE-EX file";
- return 1;
- }
- f->fmtchunkEx.dwChannelMask = SPKRS_MONO;
- break;
- case(MC_STEREO):
- if(props->chans /*!=*/ < 2){
- rsferrno = ESFBADPARAM;
- rsferrstr = "conflicting channel configuration for WAVE-EX file";
- return 1;
- }
- f->fmtchunkEx.dwChannelMask = SPKRS_STEREO;
- break;
- case(MC_QUAD):
- if(props->chans /*!=*/ < 4){
- rsferrno = ESFBADPARAM;
- rsferrstr = "conflicting channel configuration for WAVE-EX file";
- return 1;
- }
-
- f->fmtchunkEx.dwChannelMask = SPKRS_GENERIC_QUAD;
- break;
- case(MC_BFMT):
- // Nov 2005: now supporting many channel counts for B-Format!
- #ifdef NOTDEF
- if(props->chans != 4){
- rsferrno = ESFBADPARAM;
- rsferrstr = "conflicting channel configuration for WAVE-EX file";
- return 1;
- }
- #endif
- f->fmtchunkEx.dwChannelMask = SPKRS_UNASSIGNED;
- pGuid = props->samptype==FLOAT32 ?(GUID *) &SUBTYPE_AMBISONIC_B_FORMAT_IEEE_FLOAT :(GUID *) &SUBTYPE_AMBISONIC_B_FORMAT_PCM;
- break;
- case(MC_LCRS):
- if(props->chans /*!=*/< 4){
- rsferrno = ESFBADPARAM;
- rsferrstr = "conflicting channel configuration for WAVE-EX file";
- return 1;
- }
-
- f->fmtchunkEx.dwChannelMask = SPKRS_SURROUND_LCRS;
- break;
- case(MC_DOLBY_5_1):
- if(props->chans /*!=*/ < 6){
- rsferrno = ESFBADPARAM;
- rsferrstr = "conflicting channel configuration for WAVE-EX file";
- return 1;
- }
-
- f->fmtchunkEx.dwChannelMask = SPKRS_DOLBY5_1;
- break;
- /*March 2008 */
- case(MC_SURR_5_0):
- if(props->chans /*!=*/ < 5){
- rsferrno = ESFBADPARAM;
- rsferrstr = "conflicting channel configuration for WAVE-EX file";
- return 1;
- }
-
- f->fmtchunkEx.dwChannelMask = SPKRS_SURR_5_0;
- break;
- /* Nov 2013 */
-
- case(MC_SURR_6_1):
- if(props->chans < 7){
- rsferrno = ESFBADPARAM;
- rsferrstr = "conflicting channel configuration for WAVE-EX file";
- return 1;
- }
- f->fmtchunkEx.dwChannelMask = SPKRS_SURR_6_1;
- break;
- /* OCT 2009 */
- case(MC_SURR_7_1):
- if(props->chans /*!=*/ < 8){
- rsferrno = ESFBADPARAM;
- rsferrstr = "conflicting channel configuration for WAVE-EX file";
- return 1;
- }
-
- f->fmtchunkEx.dwChannelMask = SPKRS_SURR_7_1;
- break;
- case(MC_CUBE):
- if(props->chans /*!=*/ < 8){
- rsferrno = ESFBADPARAM;
- rsferrstr = "conflicting channel configuration for WAVE-EX file";
- return 1;
- }
-
- f->fmtchunkEx.dwChannelMask = SPKRS_CUBE;
- break;
- default:
- rsferrno = ESFBADPARAM;
- rsferrstr = "unsupported channel configuration for WAVE-EX file";
- return 1;
- break;
-
-
- }
-
-
- if(write_dw_msf(TAG('f','m','t',' '), f)
- ||write_dw_lsf(sizeof_WFMTEX, f) //RWD CDP97: size = 18 to include cbSize field
- #if defined _WIN32
- ||((f->fmtchunkoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF)
- ||write_w_lsf(f->fmtchunkEx.Format.wFormatTag, f)
- ||write_w_lsf(f->fmtchunkEx.Format.nChannels, f)
- ||write_dw_lsf(f->fmtchunkEx.Format.nSamplesPerSec, f)
- ||write_dw_lsf(f->fmtchunkEx.Format.nAvgBytesPerSec, f)
- ||write_w_lsf(f->fmtchunkEx.Format.nBlockAlign, f)
- ||write_w_lsf(f->fmtchunkEx.Format.wBitsPerSample, f)
- ||write_w_lsf(cbSize,f)
- )
- goto ioerror;
- #else
- ||fgetpos(f->fileno, &bytepos)
- ||write_w_lsf(f->fmtchunkEx.Format.wFormatTag, f)
- ||write_w_lsf(f->fmtchunkEx.Format.nChannels, f)
- ||write_dw_lsf(f->fmtchunkEx.Format.nSamplesPerSec, f)
- ||write_dw_lsf(f->fmtchunkEx.Format.nAvgBytesPerSec, f)
- ||write_w_lsf(f->fmtchunkEx.Format.nBlockAlign, f)
- ||write_w_lsf(f->fmtchunkEx.Format.wBitsPerSample, f)
- ||write_w_lsf(cbSize,f)
- )
- goto ioerror;
- f->fmtchunkoffset = bytepos;
-
- #endif
- //don't need fact chunk unless actually a compressed format...
-
- guid = *pGuid;
- #ifdef MSBFIRST
- guid.Data1 = REVDWBYTES(guid.Data1);
- guid.Data2 = REVWBYTES(guid.Data2);
- guid.Data3 = REVWBYTES(guid.Data3);
- #endif
- if(write_w_lsf(f->fmtchunkEx.Samples.wValidBitsPerSample,f)
- || write_dw_lsf(f->fmtchunkEx.dwChannelMask,f)
- || dowrite(f,(char *) &guid,sizeof(GUID)) /* RWD NB deal with byte-reversal sometime! */
- )
- goto ioerror;
-
- // ADD the PEAK chunk
- if((f->min_header>=SFILE_PEAKONLY) && f->peaks){
- int i,size;
- DWORD now = 0;
- for(i=0;i < props->chans; i++){
- f->peaks[i].value = 0.0f;
- f->peaks[i].position = 0;
- }
- size = 2 * sizeof(DWORD) + props->chans * sizeof(CHPEAK);
- if(write_dw_msf(TAG('P','E','A','K'),f)
- || write_dw_lsf(size,f)
- #if defined _WIN32
- || ((f->peakchunkoffset = SetFilePointer(f->fileno,0L,NULL, FILE_CURRENT))== 0xFFFFFFFF)
- || write_dw_lsf(CURRENT_PEAK_VERSION,f)
- || write_dw_lsf(now,f)
- || write_peak_lsf(props->chans,f))
-
- goto ioerror;
- #else
- || fgetpos(f->fileno, &bytepos)
- || write_dw_lsf(CURRENT_PEAK_VERSION,f)
- || write_dw_lsf(now,f)
- || write_peak_lsf(props->chans,f))
-
- goto ioerror;
- f->peakchunkoffset = bytepos;
- #endif
- }
-
-
- if(f->min_header>=SFILE_CDP){
- /*
- * add the cue point/note chunk for properties
- */
- //RWD TODO: add switch to skip writing this extra stuff!
- if(write_dw_msf(TAG('c','u','e',' '), f)
- ||write_dw_lsf(sizeof(struct cuepoint) + sizeof(DWORD), f) )
- goto ioerror;
-
- cue.name = TAG('s','f','i','f');
- cue.position = 0;
- cue.incchunkid = TAG('d','a','t','a');
- cue.chunkoffset = 0;
- cue.blockstart = 0;
- cue.sampleoffset = 0;
- if(write_dw_lsf(1, f) /* one cue point */
- ||write_dw_msf(cue.name, f)
- ||write_dw_lsf(cue.position, f)
- ||write_dw_msf(cue.incchunkid, f)
- ||write_dw_lsf(cue.chunkoffset, f)
- ||write_dw_lsf(cue.blockstart, f)
- ||write_dw_lsf(cue.sampleoffset, f) )
- goto ioerror;
-
- /*... add a LIST chunk of type 'adtl'... */
-
- if(write_dw_msf(TAG('L','I','S','T'), f)
- ||write_dw_lsf(sizeof(DWORD) + 3*sizeof(DWORD) + PROPCNKSIZE, f)
- ||write_dw_msf(TAG('a','d','t','l'), f) )
- goto ioerror;
-
- /* add the property-space note chunk */
- if(write_dw_msf(TAG('n','o','t','e'), f)
- ||write_dw_lsf(sizeof(DWORD) + PROPCNKSIZE, f)
- ||write_dw_msf(TAG('s','f','i','f'), f)
- #if defined _WIN32
- ||((f->propoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF)
- ||SetFilePointer(f->fileno, (long)PROPCNKSIZE,NULL, FILE_CURRENT) == 0xFFFFFFFF )
- goto ioerror;
- #else
- ||fgetpos(f->fileno, &bytepos)
- ||fseek(f->fileno, (long)PROPCNKSIZE, SEEK_CUR) < 0)
- goto ioerror;
- f->propoffset = bytepos;
-
- #endif
- f->propschanged = 1;
- f->proplim = PROPCNKSIZE;
- }
-
- /*
- * and add the data chunk
- */
- f->datachunksize = 0;
-
- if(write_dw_msf(TAG('d','a','t','a'), f)
- ||write_dw_lsf(0, f)
- #if defined _WIN32
- ||((f->datachunkoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF))
- goto ioerror;
- #else
- ||fgetpos(f->fileno, &bytepos))
-
- goto ioerror;
- f->datachunkoffset = bytepos;
- #endif
- f->header_set = 1; //later, may allow update prior to first write ?
- return 0;
- /* NOTREACHED */
-
- ioerror:
- rsferrno = ESFWRERR;
- rsferrstr = "error writing wav_ex header";
- return 1;
- }
- /*
- * aiff routines
- */
- //RWD98 BUG, SOMEWHERE: THIS READS THE SSND CHUNK, AND GETS SIZE = REMAIN; BUT REMAIN SHOULD BE SIZE + 8
- // SO, EITHER BUG IN THIS CODE, OR IN WRAIFFHDR... SO CANNOT USE WINDOWS DWORD 'COS UNSIGNED....
- //RWD.6.99 NOTE: some tests require the Fomat field to be set, even though this is aiff
- //RWD.7.99: accept masked AIFF formats: container size is always next intergral number of bytes
- static int
- rdaiffhdr(struct sf_file *f)
- {
- DWORD /*long */ tag, size = 0, remain = 0, appltag; //RWD.04.98 can't be unsigned until the size anomalies are resolved
- DWORD peaktime; /* RWD Jan 2005 */
- int commseen = 0, ssndseen = 0;
- DWORD numsampleframes;
- DWORD ssnd_offset, ssnd_blocksize;
- fpos_t bytepos;
- POS64(bytepos) = 0;
- char *propspace;
- DWORD peak_version;
- // WARNING! The file can have the wrong size (e.g. from sox)
- if(read_dw_msf(&tag, f)
- ||read_dw_msf(&remain, f)
- ||tag != TAG('F','O','R','M')) {
- rsferrno = ESFNOTFOUND;
- rsferrstr = "File is not an AIFF file";
- return 1;
- }
- if(remain < 3*sizeof(DWORD)) {
- rsferrno = ESFNOTFOUND;
- rsferrstr = "File data size is too small";
- return 1;
- }
- if(read_dw_msf(&tag, f)
- ||tag != TAG('A','I','F','F')) {
- rsferrno = ESFNOTFOUND;
- rsferrstr = "File does not include an AIFF form";
- return 1;
- }
- f->mainchunksize = remain;
- f->extrachunksizes = 0;
- POS64(f->propoffset) = -1;
- f->aiffchunks = 0;
- remain -= sizeof(DWORD);
- while(remain > 0) {
- if(read_dw_msf(&tag, f)
- ||read_dw_msf(&size,f)){
- if(ssndseen && commseen){ //RWD accept the file anyway if we have enough
- remain = 0;
- break;
- }
- else
- goto ioerror;
- }
- remain -= 2*sizeof(DWORD);
- switch(tag) {
- case TAG('C','O','M','M'):
- if(size != 18) {
- rsferrno = ESFNOTFOUND;
- rsferrstr = "AIFF COMM chunk of incorrect size";
- return 1;
- }
- #if defined _WIN32
- if((f->fmtchunkoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF
- ||read_w_msf(&f->fmtchunkEx.Format.nChannels, f)
- ||read_dw_msf(&numsampleframes, f)
- ||read_w_msf(&f->fmtchunkEx.Format.wBitsPerSample, f)
- ||read_ex_todw(&f->fmtchunkEx.Format.nSamplesPerSec, f) )
- goto ioerror;
- #else
- if(fgetpos(f->fileno, &bytepos)
- ||read_w_msf(&f->fmtchunkEx.Format.nChannels, f)
- ||read_dw_msf(&numsampleframes, f)
- ||read_w_msf(&f->fmtchunkEx.Format.wBitsPerSample, f)
- ||read_ex_todw(&f->fmtchunkEx.Format.nSamplesPerSec, f) )
- goto ioerror;
- f->fmtchunkoffset = bytepos;
- #endif
- /*RWD Trevor uses srate of zero for envel files! */
- /* nSamples... is unsigned anyway, so dont bother with this one any more... */
- #ifdef NOTDEF
- if(f->fmtchunkEx.Format.nSamplesPerSec < 0) {
- rsferrno = ESFNOTFOUND;
- rsferrstr = "Unknown AIFF sample rate";
- return 1;
- }
- #endif
- /*RWD.7.99 we now read 32bit in standard AIFF as LONGS
- * we rely on the extra properties to tell if it's an analysis file */
- f->fmtchunkEx.Format.wFormatTag = WAVE_FORMAT_PCM;
- //fill in other info
- f->fmtchunkEx.Samples.wValidBitsPerSample = f->fmtchunkEx.Format.wBitsPerSample;
- //we have to deduce blockalign, and hence containersize
- switch(f->fmtchunkEx.Samples.wValidBitsPerSample){
- case(32):
- f->fmtchunkEx.Format.nBlockAlign = sizeof(/*long*/int);
- break;
- case(20):
- case(24):
- f->fmtchunkEx.Format.nBlockAlign = 3;
- break;
- case(16):
- f->fmtchunkEx.Format.nBlockAlign = sizeof(short);
- break;
- case(8):
- f->fmtchunkEx.Format.nBlockAlign = sizeof(char);
- break;
- default:
- rsferrno = ESFNOTFOUND;
- rsferrstr = "unsupported sample size in aiff file";
- return 1;
- }
- f->fmtchunkEx.Format.nBlockAlign *= f->fmtchunkEx.Format.nChannels;
- //should do avgBytesPerSec too...
- f->fmtchunkEx.dwChannelMask = 0;
- remain -= 18;
- commseen++;
- break;
- //RWD.5.99 read PEAK chunk
- case TAG('P','E','A','K'):
- f->peaks = (CHPEAK *) calloc(f->fmtchunkEx.Format.nChannels,sizeof(CHPEAK));
- if(f->peaks == NULL){
- rsferrno = ESFNOMEM;
- rsferrstr = "No memory for peak data";
- return 1;
- }
- if(read_dw_msf(&peak_version,f))
- goto ioerror;
- switch(peak_version){
- case(CURRENT_PEAK_VERSION):
- if(read_dw_msf(&peaktime,f)) /* RWD Jan 2005 for DevCPP */
- goto ioerror;
- f->peaktime = (time_t) peaktime;
- #if defined _WIN32
- if((f->peakchunkoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF
- || read_peak_msf(f->fmtchunkEx.Format.nChannels,f))
- goto ioerror;
- #else
- if(fgetpos(f->fileno, &bytepos)
- || read_peak_msf(f->fmtchunkEx.Format.nChannels,f))
- goto ioerror;
- f->peakchunkoffset = bytepos;
- #endif
- break;
- default:
- #ifdef _DEBUG
- fprintf(stderr,"\nunknown PEAK version!");
- #endif
- free(f->peaks);
- f->peaks = NULL;
- break;
- }
- remain -= 2 * sizeof(DWORD) + (sizeof(CHPEAK) * f->fmtchunkEx.Format.nChannels);
- break;
- case TAG('S','S','N','D'):
- if(read_dw_msf(&ssnd_offset, f)
- ||read_dw_msf(&ssnd_blocksize, f)
- #if defined _WIN32
- ||(f->datachunkoffset = SetFilePointer(f->fileno, 0L,NULL,FILE_CURRENT)) ==0xFFFFFFFF
- || SetFilePointer(f->fileno, ((size+1)&~1) - 2 *sizeof(DWORD),NULL,FILE_CURRENT) ==0xFFFFFFFF)
- goto ioerror;
- #else
- || fgetpos(f->fileno, &bytepos))
- goto ioerror;
- f->datachunkoffset = bytepos;
- POS64(bytepos) += ((size+1)&~1) - 2 *sizeof(DWORD);
- /*fseek(f->fileno, ((size+1)&~1) - 2 *sizeof(DWORD), SEEK_CUR) < 0) */
- if(fsetpos(f->fileno,&bytepos))
- goto ioerror;
- #endif
- remain -= 2 * sizeof(DWORD); /* RWD Apr 2011 need this */
- /* RWD MAR 2015 eliminate warning, ssnd_offset is unsigned */
- if(/* ssnd_offset < 0 || */ ssnd_offset > ssnd_blocksize) {
- rsferrno = ESFNOTFOUND;
- rsferrstr = "Funny offset in AIFF SSND chunk";
- return 1;
- }
- POS64(f->datachunkoffset) += ssnd_offset;
- ssndseen++;
- remain -= (size+1)&~1; //RWD98 BUG!!! remain can get less than size...
- break;
- case 0:
- rsferrno = ESFNOTFOUND;
- rsferrstr = "Illegal zero tag in aiff chunk";
- return 1;
- case TAG('A','P','P','L'):
- if(size < sizeof(DWORD)
- ||read_dw_msf(&appltag,f) )
- goto ioerror;
- if(appltag == TAG('s','f','i','f')) {
- if(POS64(f->propoffset) >= 0
- ||(propspace = (char *) malloc(size - sizeof(DWORD))) == 0
- #if defined _WIN32
- ||(f->propoffset = SetFilePointer(f->fileno, 0L,NULL,FILE_CURRENT))==0xFFFFFFFF
- ||doread(f, propspace, size-sizeof(DWORD)) )
- goto ioerror;
- #else
- ||fgetpos(f->fileno, &bytepos)
- ||doread(f, propspace, size-sizeof(DWORD)) )
- goto ioerror;
- POS64(f->propoffset) = POS64(bytepos);
- #endif
- f->proplim = size - sizeof(DWORD);
- parseprops(f, propspace);
- if(size&1)
- doread(f, propspace, 1);
- free(propspace);
- break;
- } else {
- #if defined _WIN32
- if(SetFilePointer(f->fileno,-4L,NULL,FILE_CURRENT) == 0xFFFFFFFF)
- #else
- if(fseek(f->fileno, -4L, SEEK_CUR) < 0)
- #endif
- goto ioerror;
- }
- /* FALLTHROUGH */
- default:
- /* RWD MAR 2015: size is unsigned, eliminate warning! */
- #ifdef NOTDEF
- if(size < 0 /* || size > 100*1024 */) { /* RWD Apr 2011 */
- rsferrno = ESFNOTFOUND;
- rsferrstr = "Silly size for unknown AIFF chunk";
- return 1;
- }
- #endif
- if(ssndseen) {
- struct aiffchunk **cpp, *cp;
- for(cpp = &f->aiffchunks; *cpp != 0; cpp = &(*cpp)->next)
- ;
- if((*cpp = cp = ALLOC(struct aiffchunk)) == 0
- ||(cp->buf = (char *) malloc((size+1)&~1)) == 0) {
- rsferrno = ESFNOMEM;
- rsferrstr = "No memory for aiff chunk storage";
- return 1;
- }
- cp->tag = tag;
- cp->size = size;
- cp->next = 0;
- #if defined _WIN32
- if((cp->offset = SetFilePointer(f->fileno,0L,NULL,FILE_CURRENT)) == 0xFFFFFFFF
- ||doread(f, cp->buf, (size+1)&~1))
- goto ioerror;
- #else
- if(fgetpos(f->fileno,&bytepos)
- ||doread(f, cp->buf, (size+1)&~1))
- goto ioerror;
- cp->offset = bytepos;
- #endif
- } else {
- #if defined _WIN32
- if(SetFilePointer(f->fileno,(long)((size+1)&~1),NULL,FILE_CURRENT) == 0xFFFFFFFF)
- #else
- if(fseeko(f->fileno, (size+1)&~1, SEEK_CUR) < 0)
- #endif
- goto ioerror;
- }
- f->extrachunksizes += ((size+1)&~1) + 2*sizeof(DWORD);
- remain -= (size+1)&~1;
- break;
- }
- }
- if(!commseen) {
- rsferrno = ESFNOTFOUND;
- rsferrstr = "AIFF format error: no COMM chunk found";
- return 1;
- }
- if(!ssndseen) {
- rsferrno = ESFNOTFOUND;
- rsferrstr = "AIFF format error: no SSND chunk found";
- return 1;
- }
- f->datachunksize = numsampleframes * f->fmtchunkEx.Format.nChannels;
- switch(f->fmtchunkEx.Format.wBitsPerSample) {
- case 32: /* floats */
- f->datachunksize *= 4;
- break;
- case 20:
- case 24:
- f->datachunksize *= 3;
- break;
- case 16: /* shorts */
- f->datachunksize *= 2;
- break;
- case 8: /* byte -> short mappping */
- f->datachunksize *= 2; /* looks like short samples! */
- break;
- default:
- rsferrno = ESFNOTFOUND;
- rsferrstr = "can't open aiff file - unsupported wordsize";
- return 1;
- }
- #if defined _WIN32
- if(SetFilePointer(f->fileno,f->datachunkoffset,NULL,FILE_BEGIN)==0xFFFFFFFF)
- #else
- bytepos = f->datachunkoffset;
- if(fsetpos(f->fileno, &bytepos) < 0)
- #endif
- goto ioerror;
- return 0;
- /* NOTREACHED */
- ioerror:
- rsferrno = ESFRDERR;
- rsferrstr = "read error (or file too short) reading AIFF header";
- return 1;
- }
- /*AIF-C*/
- #define AIFC_VERSION_1 (0xA2805140)
- static int
- rdaifchdr(struct sf_file *f)
- {
- DWORD tag, size = 0, remain = 0, appltag;
- int commseen = 0, ssndseen = 0,fmtverseen = 0;
- DWORD numsampleframes, aifcver,ID_compression;
- DWORD ssnd_offset, ssnd_blocksize;
- char *propspace;
- DWORD peak_version;
- DWORD peaktime;
- fpos_t bytepos;
- if(read_dw_msf(&tag, f)
- ||read_dw_msf(&remain, f)
- ||tag != TAG('F','O','R','M')) {
- rsferrno = ESFNOTFOUND;
- rsferrstr = "File is not an AIFF file";
- return 1;
- }
- if(remain < 3*sizeof(DWORD)) {
- rsferrno = ESFNOTFOUND;
- rsferrstr = "File data size is too small";
- return 1;
- }
- if(read_dw_msf(&tag, f)
- ||tag != TAG('A','I','F','C')) {
- rsferrno = ESFNOTFOUND;
- rsferrstr = "File does not include an AIFC form";
- return 1;
- }
- f->mainchunksize = remain;
- f->extrachunksizes = 0;
- POS64(f->propoffset) = -1;
- f->aiffchunks = 0;
- //start by assuming integer format:
- f->fmtchunkEx.Format.wFormatTag = WAVE_FORMAT_PCM;
- remain -= sizeof(DWORD);
- while(remain > 0) {
- if(read_dw_msf(&tag, f)
- ||read_dw_msf(&size,f)){
- if(ssndseen && commseen){ //RWD accept the file anyway if we have enough
- remain = 0;
- break;
- }
- else
- goto ioerror;
- }
- remain -= 2*sizeof(DWORD);
- switch(tag) {
- case TAG('F','V','E','R'):
- if(size != 4){
- rsferrno = ESFNOTFOUND;
- rsferrstr = "bad aif-c FVER chunk";
- return 1;
- }
- if(read_dw_msf(&aifcver,f) || aifcver != AIFC_VERSION_1){
- rsferrno = ESFNOTFOUND;
- rsferrstr = "bad aif-c Version";
- return 1;
- }
- remain -= sizeof(DWORD);
- fmtverseen++;
- break;
- case TAG('C','O','M','M'):
- if(size < 22) {
- rsferrno = ESFNOTFOUND;
- rsferrstr = "AIFC COMM chunk of incorrect size";
- return 1;
- }
- #if defined _WIN32
- if((f->fmtchunkoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF
- ||read_w_msf(&f->fmtchunkEx.Format.nChannels, f)
- ||read_dw_msf(&numsampleframes, f)
- ||read_w_msf(&f->fmtchunkEx.Format.wBitsPerSample, f)
- ||read_ex_todw(&f->fmtchunkEx.Format.nSamplesPerSec, f) )
- goto ioerror;
- #else
- if(fgetpos(f->fileno, &bytepos)
- ||read_w_msf(&f->fmtchunkEx.Format.nChannels, f)
- ||read_dw_msf(&numsampleframes, f)
- ||read_w_msf(&f->fmtchunkEx.Format.wBitsPerSample, f)
- ||read_ex_todw(&f->fmtchunkEx.Format.nSamplesPerSec, f) )
- goto ioerror;
- f->fmtchunkoffset = bytepos;
- #endif
- /*RWD: Trevor uses srate of zero for envel files! */
- /* RWD MAR 2015: so eliminate code to avoid warning, as above */
- #ifdef NOTDEF
- if(f->fmtchunkEx.Format.nSamplesPerSec < 0) {
- rsferrno = ESFNOTFOUND;
- rsferrstr = "Unknown AIFC sample rate";
- return 1;
- }
- #endif
- if(read_dw_msf(&ID_compression,f))
- goto ioerror;
- if( !(
- (ID_compression == TAG('N','O','N','E'))
- || (ID_compression == TAG('F','L','3','2')) //Csound
- || (ID_compression == TAG('f','l','3','2')) //Apple
- /* used in Steinberg 24bit SDIR files */
- || (ID_compression == TAG('i','n','2','4'))
- )){
- rsferrno = ESFNOTFOUND;
- rsferrstr = "Unknown AIFC compression type";
- return 1;
- }
- //set sample type in sfinfo
- if((ID_compression== TAG('F','L','3','2'))
- || ID_compression == TAG('f','l','3','2')){
- /*Nov 2001: F***** Quicktime writes size = 16, for floats! */
- if(f->fmtchunkEx.Format.wBitsPerSample != 32){
- if(f->fmtchunkEx.Format.wBitsPerSample != 16){
- rsferrno = ESFNOTFOUND;
- rsferrstr = "error in AIFC header: samples not 32bit in floats file ";
- return 1;
- }
- else
- f->fmtchunkEx.Format.wBitsPerSample = 32;
- }
- f->fmtchunkEx.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
- }
- /* RWD 06/01/09 precautionary, to validate 'in24' 24bit files */
- if(ID_compression == TAG('i','n','2','4')) {
- if(f->fmtchunkEx.Format.wBitsPerSample != 24){
- rsferrstr = "error in AIFC header: sample size not 24bit in <in24> file ";
- return 1;
- }
- }
- //no ambiguity here with 32bit format.
- //fill in other info
- f->fmtchunkEx.Samples.wValidBitsPerSample = f->fmtchunkEx.Format.wBitsPerSample;
- f->fmtchunkEx.dwChannelMask = 0;
- //we have to deduce blockalign, and hence containersize
- switch(f->fmtchunkEx.Samples.wValidBitsPerSample){
- case(32):
- f->fmtchunkEx.Format.nBlockAlign = sizeof(/*long*/int);
- break;
- case(20):
- case(24):
- f->fmtchunkEx.Format.nBlockAlign = 3;
- break;
- case(16):
- f->fmtchunkEx.Format.nBlockAlign = sizeof(short);
- break;
- case(8):
- f->fmtchunkEx.Format.nBlockAlign = sizeof(char);
- break;
- default:
- rsferrno = ESFNOTFOUND;
- rsferrstr = "unsupported sample size in aiff file";
- return 1;
- }
- f->fmtchunkEx.Format.nBlockAlign *= f->fmtchunkEx.Format.nChannels;
- //should do avgBytesPerSec too...
- /*RWD 23:10:2000 can get odd sizes... */
- //skip past pascal string
- #if defined _WIN32
- if(SetFilePointer(f->fileno, ((size+1)&~1) - 22,NULL,FILE_CURRENT) ==0xFFFFFFFF)
- #else
- if(fseek(f->fileno,((size+1)&~1) - 22,SEEK_CUR) < 0)
- #endif
- goto ioerror;
- remain -= (size+1)&~1;
- commseen++;
- break;
- //RWD.5.99 read PEAK chunk
- case TAG('P','E','A','K'):
- f->peaks = (CHPEAK *) calloc(f->fmtchunkEx.Format.nChannels,sizeof(CHPEAK));
- if(f->peaks == NULL){
- rsferrno = ESFNOMEM;
- rsferrstr = "No memory for peak data";
- return 1;
- }
- if(read_dw_msf(&peak_version,f))
- goto ioerror;
- switch(peak_version){
- case(CURRENT_PEAK_VERSION):
- if(read_dw_msf(&peaktime,f))
- goto ioerror;
- f->peaktime = (time_t) peaktime;
- #if defined _WIN32
- if((f->peakchunkoffset = SetFilePointer(f->fileno, 0L, NULL, FILE_CURRENT)) == 0xFFFFFFFF
- || read_peak_msf(f->fmtchunkEx.Format.nChannels,f))
- goto ioerror;
- #else
- if(fgetpos(f->fileno, &bytepos)
- || read_peak_msf(f->fmtchunkEx.Format.nChannels,f))
- goto ioerror;
- f->peakchunkoffset = bytepos;
- #endif
- break;
- default:
- #ifdef _DEBUG
- fprintf(stderr,"\nunknown PEAK version!");
- #endif
- free(f->peaks);
- f->peaks = NULL;
- break;
- }
- remain -= 2 * sizeof(DWORD) + (sizeof(CHPEAK) * f->fmtchunkEx.Format.nChannels);
- break;
- case TAG('S','S','N','D'):
- if(read_dw_msf(&ssnd_offset, f)
- ||read_dw_msf(&ssnd_blocksize, f)
- #if defined _WIN32
- ||(f->datachunkoffset = SetFilePointer(f->fileno, 0L,NULL,FILE_CURRENT)) ==0xFFFFFFFF
- || SetFilePointer(f->fileno, ((size+1)&~1) - 2 *sizeof(DWORD),NULL,FILE_CURRENT) ==0xFFFFFFFF)
- goto ioerror;
- if(ssnd_offset < 0 || ssnd_offset > ssnd_blocksize) {
- rsferrno = ESFNOTFOUND;
- rsferrstr = "Funny offset in AIFC SSND chunk";
- return 1;
- }
- f->datachunkoffset += ssnd_offset;
- #else
- ||fgetpos(f->fileno, &bytepos) )
- goto ioerror;
- f->datachunkoffset = bytepos;
- POS64(bytepos) = ((size+1)&~1) - 2 *sizeof(DWORD);
- if(fseeko(f->fileno,POS64(bytepos), SEEK_CUR) < 0)
- goto ioerror;
- /* RWD MAR 2015 ssnd_offset unsigned, eliminate compiler warning */
- if(/* ssnd_offset < 0 || */ ssnd_offset > ssnd_blocksize) {
- rsferrno = ESFNOTFOUND;
- rsferrstr = "Funny offset in AIFC SSND chunk";
- return 1;
- }
- POS64(f->datachunkoffset) += ssnd_offset;
- #endif
- ssndseen++;
- remain -= (size+1)&~1; //RWD98 BUG!!! remain can get less than size...
- break;
- case 0:
- rsferrno = ESFNOTFOUND;
- rsferrstr = "Illegal zero tag in aifc chunk";
- return 1;
- case TAG('A','P','P','L'):
- if(size < sizeof(DWORD)
- ||read_dw_msf(&appltag,f) )
- goto ioerror;
- if(appltag == TAG('s','f','i','f')) {
- if(POS64(f->propoffset) >= 0
- ||(propspace = (char *) malloc(size - sizeof(DWORD))) == 0
- #if defined _WIN32
- ||(f->propoffset = SetFilePointer(f->fileno, 0L,NULL,FILE_CURRENT))==0xFFFFFFFF
- ||doread(f, propspace, size-sizeof(DWORD)) )
- goto ioerror;
- #else
- ||fgetpos(f->fileno, &bytepos)
- ||doread(f, propspace, size-sizeof(DWORD)) )
- goto ioerror;
- f->propoffset = bytepos;
- #endif
- f->proplim = size - sizeof(DWORD);
- parseprops(f, propspace);
- if(size&1)
- doread(f, propspace, 1);
- free(propspace);
- break;
- } else {
- #if defined _WIN32
- if(SetFilePointer(f->fileno,-4L,NULL,FILE_CURRENT) == 0xFFFFFFFF)
- #else
- if(fseek(f->fileno, -4L, SEEK_CUR) < 0)
- #endif
- goto ioerror;
- }
- /* FALLTHROUGH */
- default:
- /* RWD MAR 2015 eliminate compiler warning; bit of an arbitrary exclusion anyway? */
- if(/* size < 0 || */ size > 100*1024) {
- rsferrno = ESFNOTFOUND;
- rsferrstr = "Silly size for unknown AIFC chunk";
- return 1;
- }
- if(ssndseen) {
- struct aiffchunk **cpp, *cp;
- for(cpp = &f->aiffchunks; *cpp != 0; cpp = &(*cpp)->next)
- ;
- if((*cpp = cp = ALLOC(struct aiffchunk)) == 0
- ||(cp->buf = (char *) malloc((size+1)&~1)) == 0) {
- rsferrno = ESFNOMEM;
- rsferrstr = "No memory for aifc chunk storage";
- return 1;
- }
- cp->tag = tag;
- cp->size = size;
- cp->next = 0;
- #if defined _WIN32
- if((cp->offset = SetFilePointer(f->fileno,0L,NULL,FILE_CURRENT)) == 0xFFFFFFFF
- ||doread(f, cp->buf, (size+1)&~1))
- goto ioerror;
- #else
- if(fgetpos(f->fileno, &bytepos)
- ||doread(f, cp->buf, (size+1)&~1))
- goto ioerror;
- cp->offset = bytepos;
- #endif
- } else {
- #if defined _WIN32
- if(SetFilePointer(f->fileno,(long)((size+1)&~1),NULL,FILE_CURRENT) == 0xFFFFFFFF)
- goto ioerror;
- #else
- if(fgetpos(f->fileno, &bytepos))
- goto ioerror;
- POS64(bytepos) += (size+1)&~1;
- if(fsetpos(f->fileno, &bytepos))
- goto ioerror;
- #endif
- }
- f->extrachunksizes += ((size+1)&~1) + 2*sizeof(DWORD);
- remain -= (size+1)&~1;
- break;
- }
- }
- if(!commseen) {
- rsferrno = ESFNOTFOUND;
- rsferrstr = "AIFC format error: no COMM chunk found";
- return 1;
- }
- if(!ssndseen) {
- rsferrno = ESFNOTFOUND;
- rsferrstr = "AIFC format error: no SSND chunk found";
- return 1;
- }
- if(!fmtverseen) {
- rsferrno = ESFNOTFOUND;
- rsferrstr = "AIFC format error: no FVER chunk found";
- return 1;
- }
- f->datachunksize = numsampleframes * f->fmtchunkEx.Format.nChannels;
- switch(f->fmtchunkEx.Format.wBitsPerSample) {
- case 32: /* floats */
- f->datachunksize *= 4;
- break;
- case 16: /* shorts */
- f->datachunksize *= 2;
- break;
- case 20:
- case 24:
- f->datachunksize *= 3;
- break;
- case 8: /* byte -> short mappping */
- f->datachunksize *= 2; /* looks like short samples! */
- break;
- default:
- rsferrno = ESFNOTFOUND;
- rsferrstr = "can't open Sfile - unsupported wordsize";
- return 1;
- }
- #if defined _WIN32
- if(SetFilePointer(f->fileno,f->datachunkoffset,NULL,FILE_BEGIN)==0xFFFFFFFF)
- #else
- POS64(bytepos) = POS64(f->datachunkoffset);
- if(fsetpos(f->fileno, &bytepos) < 0)
- #endif
- goto ioerror;
- return 0;
- /* NOTREACHED */
- ioerror:
- rsferrno = ESFRDERR;
- rsferrstr = "read error (or file too short) reading AIFC header";
- return 1;
- }
- #if 0
- static int
- wraiffhdr(struct sf_file *f)
- {
- fpos_t bytepos;
- f->mainchunksize = 0;
- if(write_dw_msf(TAG('F','O','R','M'), f)
- ||write_dw_msf(0, f)
- ||write_dw_msf(TAG('A','I','F','F'), f) )
- goto ioerror;
- f->fmtchunkEx.Format.nChannels = 1;
- f->fmtchunkEx.Format.nSamplesPerSec = 44100;
- f->fmtchunkEx.Format.wBitsPerSample = 16;
- f->aiffchunks = 0;
- if(write_dw_msf(TAG('C','O','M','M'), f)
- || write_dw_msf(18, f)
- #if defined _WIN32
- || (f->fmtchunkoffset = SetFilePointer(f->fileno,0L,NULL,FILE_CURRENT))==0xFFFFFFFF
- || write_w_msf(f->fmtchunkEx.Format.nChannels, f)
- || write_dw_msf(0, f) /* num sample frames */
- || write_w_msf(f->fmtchunkEx.Format.wBitsPerSample, f)
- || write_dw_toex(f->fmtchunkEx.Format.nSamplesPerSec, f) )
- goto ioerror;
- #else
- ||fgetpos(f->fileno, &bytepos)
- || write_w_msf(f->fmtchunkEx.Format.nChannels, f)
- || write_dw_msf(0, f) /* num sample frames */
- || write_w_msf(f->fmtchunkEx.Format.wBitsPerSample, f)
- || write_dw_toex(f->fmtchunkEx.Format.nSamplesPerSec, f) )
- goto ioerror;
- f->fmtchunkoffset = bytepos;
- #endif
- if(write_dw_msf(TAG('A','P','P','L'), f)
- || write_dw_msf(sizeof(DWORD) + PROPCNKSIZE, f)
- || write_dw_msf(TAG('s','f','i','f'), f)
- #if defined _WIN32
- || (f->propoffset = SetFilePointer(f->fileno, 0L,NULL,FILE_CURRENT))==0xFFFFFFFF
- || SetFilePointer(f->fileno,(long)PROPCNKSIZE,NULL,FILE_CURRENT) == 0xFFFFFFFF)
- goto ioerror;
- #else
- || fgetpos(f->fileno, &bytepos)
- || fseek(f->fileno, (long)PROPCNKSIZE, SEEK_CUR) < 0)
- goto ioerror;
- f->propoffset = bytepos;
- #endif
- if(write_dw_msf(TAG('S','S','N','D'), f)
- || write_dw_msf(0, f)
- || write_dw_msf(0, f) /* offset */
- || write_dw_msf(0, f) /* blocksize */
- #if defined _WIN32
- || (f->datachunkoffset = SetFilePointer(f->fileno,0L,NULL,FILE_CURRENT)) == 0xFFFFFFFF)
- goto ioerror;
- #else
- || fgetpos(f->fileno, &bytepos) )
- goto ioerror;
- f->datachunkoffset = bytepos;
- #endif
- f->propschanged = 1;
- f->proplim = PROPCNKSIZE;
- f->datachunksize = 0;
- f->extrachunksizes = 0;
- return 0;
- /* NOTREACHED */
- ioerror:
- rsferrno = ESFWRERR;
- rsferrstr = "write error writing aiff header";
- return 1;
- }
- #endif
- /*********** sfsys98 extension **********/
- static int
- wraiffhdr98(struct sf_file *f,int channels,int srate,int stype)
- {
- fpos_t bytepos;
- if(stype >= SAMP_MASKED)
- return 1;
- rsferrstr = NULL;
- f->mainchunksize = 0;
- if(write_dw_msf(TAG('F','O','R','M'), f)
- || write_dw_msf(0, f)
- || write_dw_msf(TAG('A','I','F','F'), f) )
- goto ioerror;
- f->fmtchunkEx.Format.nChannels = (short)channels;
- f->fmtchunkEx.Format.nSamplesPerSec = srate;
- switch(stype){
- case(SAMP_SHORT):
- f->fmtchunkEx.Format.wBitsPerSample = 16;
- f->fmtchunkEx.Format.nBlockAlign = sizeof(short) * f->fmtchunkEx.Format.nChannels;
- break;
- case(SAMP_FLOAT): //need to keep this for now...
- case(SAMP_LONG):
- f->fmtchunkEx.Format.wBitsPerSample = 32;
- f->fmtchunkEx.Format.nBlockAlign = sizeof(/*long*/int) * f->fmtchunkEx.Format.nChannels;
- break;
- case(SAMP_2024):
- f->fmtchunkEx.Format.wBitsPerSample = 20;
- f->fmtchunkEx.Format.nBlockAlign = 3 * f->fmtchunkEx.Format.nChannels;
- break;
- case(SAMP_2424):
- f->fmtchunkEx.Format.wBitsPerSample = 24;
- f->fmtchunkEx.Format.nBlockAlign = 3 * f->fmtchunkEx.Format.nChannels;
- break;
- //NB 24/32 not allowed in AIFF
- //case SAMP_MASKED: supported by AIFF, inside nearest integral byte-size
- default:
- rsferrstr = "sample format not supported in AIFF files";
- goto ioerror; //something we don't know about!
- }
- f->aiffchunks = 0;
- if(write_dw_msf(TAG('C','O','M','M'), f)
- || write_dw_msf(18, f)
- #if defined _WIN32
- || (f->fmtchunkoffset = SetFilePointer(f->fileno,0L,NULL,FILE_CURRENT))==0xFFFFFFFF
- || write_w_msf(f->fmtchunkEx.Format.nChannels, f)
- || write_dw_msf(0, f) /* num sample frames */
- || write_w_msf(f->fmtchunkEx.Format.wBitsPerSample, f)
- || write_dw_toex(f->fmtchunkEx.Format.nSamplesPerSec, f) )
- goto ioerror;
- #else
- || fgetpos(f->fileno, &bytepos)
- || write_w_msf(f->fmtchunkEx.Format.nChannels, f)
- || write_dw_msf(0, f) /* num sample frames */
- || write_w_msf(f->fmtchunkEx.Format.wBitsPerSample, f)
- || write_dw_toex(f->fmtchunkEx.Format.nSamplesPerSec, f) )
- goto ioerror;
- f->fmtchunkoffset = bytepos;
- #endif
- //RWD.6.5.99 ADD the PEAK chunk
- if((f->min_header >= SFILE_PEAKONLY) && f->peaks){
- int i,size;
- DWORD now = 0;
- for(i=0;i < channels; i++){
- f->peaks[i].value = 0.0f;
- f->peaks[i].position = 0;
- }
- size = 2 * sizeof(DWORD) + channels * sizeof(CHPEAK);
- if(write_dw_msf(TAG('P','E','A','K'),f)
- || write_dw_msf(size,f)
- #if defined _WIN32
- || ((f->peakchunkoffset = SetFilePointer(f->fileno,0L,NULL, FILE_CURRENT))== 0xFFFFFFFF)
- || write_dw_msf(CURRENT_PEAK_VERSION,f)
- || write_dw_msf(now,f)
- || write_peak_msf(channels,f))
- goto ioerror;
- #else
- || fgetpos(f->fileno, &bytepos)
- || write_dw_msf(CURRENT_PEAK_VERSION,f)
- || write_dw_msf(now,f)
- || write_peak_msf(channels,f))
- goto ioerror;
- f->peakchunkoffset = bytepos;
- #endif
- }
- if(f->min_header >= SFILE_CDP){
- if(write_dw_msf(TAG('A','P','P','L'), f)
- || write_dw_msf(sizeof(DWORD) + PROPCNKSIZE, f)
- || write_dw_msf(TAG('s','f','i','f'), f)
- #if defined _WIN32
- || (f->propoffset = SetFilePointer(f->fileno, 0L,NULL,FILE_CURRENT))==0xFFFFFFFF
- || SetFilePointer(f->fileno,(long)PROPCNKSIZE,NULL,FILE_CURRENT) == 0xFFFFFFFF)
- goto ioerror;
- #else
- || fgetpos(f->fileno, &bytepos)
- || fseek(f->fileno, (long)PROPCNKSIZE, SEEK_CUR) < 0)
- goto ioerror;
- f->propoffset = bytepos;
- #endif
- }
- if(write_dw_msf(TAG('S','S','N','D'), f)
- || write_dw_msf(0, f)
- || write_dw_msf(0, f) /* offset */
- || write_dw_msf(0, f) /* blocksize */
- #if defined _WIN32
- || (f->datachunkoffset = SetFilePointer(f->fileno,0L,NULL,FILE_CURRENT)) == 0xFFFFFFFF)
- goto ioerror;
- #else
- || fgetpos(f->fileno, &bytepos) )
- goto ioerror;
- f->datachunkoffset = bytepos;
- #endif
- if(f->min_header >= SFILE_CDP){
- f->propschanged = 1;
- f->proplim = PROPCNKSIZE;
- }
- f->datachunksize = 0;
- f->extrachunksizes = 0;
- f->header_set = 1;
- return 0;
- /* NOTREACHED */
- ioerror:
- rsferrno = ESFWRERR;
- if(rsferrstr == NULL)
- rsferrstr = "error writing aiff header";
- return 1;
- }
- /*RWD 22:6:2000 now use 'fl32', so the new Cubase will read it!*/
- static int
- wraifchdr(struct sf_file *f,int channels,int srate,int stype)
- {
- DWORD aifcver = AIFC_VERSION_1;
- DWORD ID_compression;
- fpos_t bytepos;
- //assume 32bit floats, but we may be asked to use aifc for integer formats too
- char *str_compressed = (char *) aifc_floatstring;
- int pstring_size = 10;
- rsferrstr = NULL;
- if(stype >= SAMP_MASKED)
- return 1;
- /*RWD Sept 2000: was "ff32!" .*/
- if(stype==SAMP_FLOAT)
- ID_compression = TAG('f','l','3','2');
- /* RWD 06-01-09 TODO: add "in24" type? */
- else {
- ID_compression = TAG('N','O','N','E');
- pstring_size = 16;
- str_compressed = (char *) aifc_notcompressed;
- }
- f->mainchunksize = 0;
- if(write_dw_msf(TAG('F','O','R','M'), f)
- ||write_dw_msf(0, f)
- ||write_dw_msf(TAG('A','I','F','C'), f) )
- goto ioerror;
- f->fmtchunkEx.Format.nChannels = (short)channels;
- f->fmtchunkEx.Format.nSamplesPerSec = srate;
- switch(stype){
- case(SAMP_SHORT):
- f->fmtchunkEx.Format.wBitsPerSample = 16;
- f->fmtchunkEx.Format.nBlockAlign = sizeof(short) * f->fmtchunkEx.Format.nChannels;
- break;
- case(SAMP_FLOAT):
- case(SAMP_LONG):
- f->fmtchunkEx.Format.wBitsPerSample = 32;
- f->fmtchunkEx.Format.nBlockAlign = sizeof(/*long*/int) * f->fmtchunkEx.Format.nChannels;
- break;
- case(SAMP_2024):
- f->fmtchunkEx.Format.wBitsPerSample = 20;
- f->fmtchunkEx.Format.nBlockAlign = 3 * f->fmtchunkEx.Format.nChannels;
- case(SAMP_2424):
- f->fmtchunkEx.Format.wBitsPerSample = 24;
- f->fmtchunkEx.Format.nBlockAlign = 3 * f->fmtchunkEx.Format.nChannels;
- break;
- //NB 2432 format not allowed in AIF file!
- default:
- rsferrstr = "requested sample format not supported by AIFF-C";
- goto ioerror; //something we don't know about!
- }
- f->aiffchunks = 0;
- //write FVER chunk
- if(write_dw_msf(TAG('F','V','E','R'),f)
- || write_dw_msf(4,f)
- || write_dw_msf(aifcver,f))
- goto ioerror;
- //extended COMM chunk...22 bytes plus size of pascal string, rounded
- if(write_dw_msf(TAG('C','O','M','M'), f)
- || write_dw_msf(22 + pstring_size, f)
- #if defined _WIN32
- || (f->fmtchunkoffset = SetFilePointer(f->fileno,0L,NULL,FILE_CURRENT))==0xFFFFFFFF
- || write_w_msf(f->fmtchunkEx.Format.nChannels, f)
- || write_dw_msf(0, f) /* num sample frames */
- || write_w_msf(f->fmtchunkEx.Format.wBitsPerSample, f)
- || write_dw_toex(f->fmtchunkEx.Format.nSamplesPerSec, f) )
- goto ioerror;
- #else
- || fgetpos(f->fileno, &bytepos)
- || write_w_msf(f->fmtchunkEx.Format.nChannels, f)
- || write_dw_msf(0, f) /* num sample frames */
- || write_w_msf(f->fmtchunkEx.Format.wBitsPerSample, f)
- || write_dw_toex(f->fmtchunkEx.Format.nSamplesPerSec, f) )
- goto ioerror;
- f->fmtchunkoffset = bytepos;
- #endif
- //now the special bits...
- if(write_dw_msf(ID_compression,f))
- goto ioerror;
- //the dreaded pascal string...
- if(dowrite(f,str_compressed,pstring_size))
- goto ioerror;
- //RWD.6.5.99 ADD the PEAK chunk
- if((f->min_header >= SFILE_PEAKONLY) && f->peaks){
- int i,size;
- DWORD now = 0;
- for(i=0;i < channels; i++){
- f->peaks[i].value = 0.0f;
- f->peaks[i].position = 0;
- }
- size = 2 * sizeof(DWORD) + channels * sizeof(CHPEAK);
- if(write_dw_msf(TAG('P','E','A','K'),f)
- || write_dw_msf(size,f)
- #if defined _WIN32
- || ((f->peakchunkoffset = SetFilePointer(f->fileno,0L,NULL, FILE_CURRENT))== 0xFFFFFFFF)
- || write_dw_msf(CURRENT_PEAK_VERSION,f)
- || write_dw_msf(now,f)
- || write_peak_msf(channels,f))
- goto ioerror;
- #else
- || fgetpos(f->fileno, &bytepos)
- || write_dw_msf(CURRENT_PEAK_VERSION,f)
- || write_dw_msf(now,f)
- || write_peak_msf(channels,f))
- goto ioerror;
- f->peakchunkoffset = bytepos;
- #endif
- }
- if(f->min_header >= SFILE_CDP){
- if(write_dw_msf(TAG('A','P','P','L'), f)
- || write_dw_msf(sizeof(DWORD) + PROPCNKSIZE, f)
- || write_dw_msf(TAG('s','f','i','f'), f)
- #if defined _WIN32
- || (f->propoffset = SetFilePointer(f->fileno, 0L,NULL,FILE_CURRENT))==0xFFFFFFFF
- || SetFilePointer(f->fileno,(long)PROPCNKSIZE,NULL,FILE_CURRENT) == 0xFFFFFFFF)
- goto ioerror;
- #else
- || fgetpos(f->fileno, &bytepos)
- || fseek(f->fileno, (long)PROPCNKSIZE, SEEK_CUR) < 0)
- goto ioerror;
- f->propoffset = bytepos;
- #endif
- }
- if(write_dw_msf(TAG('S','S','N','D'), f)
- ||write_dw_msf(0, f)
- ||write_dw_msf(0, f) /* offset */
- ||write_dw_msf(0, f) /* blocksize */
- #if defined _WIN32
- ||(f->datachunkoffset = SetFilePointer(f->fileno,0L,NULL,FILE_CURRENT)) == 0xFFFFFFFF)
- goto ioerror;
- #else
- ||fgetpos(f->fileno, &bytepos) )
- goto ioerror;
- f->datachunkoffset = bytepos;
- #endif
- if(f->min_header >= SFILE_CDP){
- f->propschanged = 1;
- f->proplim = PROPCNKSIZE;
- }
- f->datachunksize = 0;
- f->extrachunksizes = 0;
- f->header_set = 1;
- return 0;
- /* NOTREACHED */
- ioerror:
- rsferrno = ESFWRERR;
- if(rsferrstr==NULL)
- rsferrstr = "error writing aiff-c header";
- return 1;
- }
- /*
- * Initialization routines
- */
-
- static void
- rsffinish(void)
- {
- int i;
- for(i = 0; i < SF_MAXFILES; i++)
- if(sf_files[i] != 0)
- sfclose(i+SFDBASE);
- #ifdef ENABLE_PVX
- pvsys_release();
- #endif
- #ifdef _WIN32
- if(CDP_COM_READY){
- COMclose();
- CDP_COM_READY = 0;
- }
- #endif
- }
- int
- sflinit(const char *name)
- {
- int i;
- #if defined ENABLE_PVX
- init_pvsys();
- #endif
- for(i = 0; i < SF_MAXFILES; i++)
- sf_files[i] = 0;
- atexit(rsffinish);
- if(sizeof(DWORD) != 4 || sizeof(WORD) != 2) {
- rsferrno = ESFBADPARAM;
- rsferrstr = "internal: sizeof(WORD) != 2 or sizeof(DWORD) != 4";
- return -1;
- }
- #ifdef _WIN32
- //alternative is to set CDP_COM_READY entirely in shortcuts.c
- #ifdef _DEBUG
- assert(!CDP_COM_READY);
- #endif
- CDP_COM_READY = COMinit(); //need COM to read shortcuts
- #endif
- return 0;
- }
- /*
- * Misc other stuff
- */
- #if 0
- void
- sffinish()
- {
- /* leave everything to atexit! */
- }
- #endif
-
- char *
- sfgetbigbuf(int *secsize)
- {
- char *mem = (char *) malloc(100*SECSIZE);
- *secsize = (mem == 0) ? 0 : 100;
- return mem;
- }
- void
- sfperror(const char *s)
- {
- if(s == 0)
- s = "sound filing system";
- if(*s != '\0')
- fprintf(stderr, "%s: %s\n", s, rsferrstr);
- else
- fprintf(stderr, "%s\n", rsferrstr);
- }
- char *
- sferrstr(void)
- {
- return rsferrstr;
- }
- int
- sferrno(void)
- {
- return rsferrno;
- }
- int
- sfsetprefix(char *path)
- {
- /* the set prefix call is simply ignored - for now */
- return 0;
- }
- void
- sfgetprefix(char *path)
- {
- path[0] = '\0'; /* signal that no prefix is set */
- }
- /*
- * allocate/de-allocate file numbers
- */
- static int allocsffile(char *filename)
- {
- int i;
- int first_i = -1;
- /*#if defined CDP97 && defined _WIN32*/
- int refcnt98 = 1; //RWD incr refcnt for THIS file, if we have previously opened it
- /*#endif*/
- for(i = 0; i < SF_MAXFILES; i++)
- if(sf_files[i] == 0) {
- if(first_i < 0)
- first_i = i;
- }
-
- //RWD98 excluding the return ~seems~ to be all thats needed to get multiple opens!
- else if(_stricmp(sf_files[i]->filename, filename) == 0) {/* not quite right! */
- sf_files[i]->refcnt++;
- refcnt98++; //for THIS file
- //return i;
- }
-
- if(first_i < 0) {
- rsferrno = ESFNOSFD;
- rsferrstr = "Too many Sfiles are open";
- free(filename);
- return -1;
- }
- if((sf_files[first_i] = ALLOC(struct sf_file)) == 0) {
- rsferrno = ESFNOMEM;
- rsferrstr = "No memory for open SFfile";
- free(filename);
- return -1;
- }
- memset(sf_files[first_i],0,sizeof(struct sf_file)); // RWD defensive etc
- sf_files[first_i]->refcnt = refcnt98;
-
- //sf_files[first_i]->refcnt = 1; //RWD.6.98 restore this to restore old behaviour
-
- sf_files[first_i]->filename = filename;
- sf_files[first_i]->props = 0;
- sf_files[first_i]->proplim = 0;
- sf_files[first_i]->curpropsize = 0;
- sf_files[first_i]->propschanged = 0;
- sf_files[first_i]->aiffchunks = 0;
- sf_files[first_i]->peaktime = 0;
- POS64(sf_files[first_i]->peakchunkoffset) = 0;
- POS64(sf_files[first_i]->factchunkoffset) = 0;
- POS64(sf_files[first_i]->datachunkoffset) = 0;
- sf_files[first_i]->peaks = NULL;
- sf_files[first_i]->bitmask = 0xffffffff;
- sf_files[first_i]->fmtchunkEx.dwChannelMask = 0;
- sf_files[first_i]->chformat = STDWAVE;
- sf_files[first_i]->min_header = SFILE_CDP;
- #ifdef ENABLE_PVX
- sf_files[first_i]->pvxprops = NULL;
- #endif
- return first_i;
- }
- static void
- freesffile(int i)
- {
- struct property *pp = sf_files[i]->props;
- struct aiffchunk *ap = sf_files[i]->aiffchunks;
- while(pp != /* 0 */ NULL) {
- struct property *pnext = pp->next;
- free(pp->name);
- free(pp->data);
- free(pp);
- pp = pnext;
- }
- while(ap != /* 0 */ NULL) {
- struct aiffchunk *anext = ap->next;
- free(ap->buf);
- free(ap);
- ap = anext;
- }
- free(sf_files[i]->filename);
- //RWD.6.5.99
- if(sf_files[i]->peaks != NULL)
- free(sf_files[i]->peaks);
- #ifdef ENABLE_PVX
- if(sf_files[i]->pvxprops != NULL)
- free(sf_files[i]->pvxprops);
- #endif
- free(sf_files[i]);
- sf_files[i] = /* 0 */ NULL;
- }
- #ifdef unix
- #define PATH_SEP '/'
- #else
- #define PATH_SEP '\\'
- #endif
- //RWD: the environment var code prevents use of a defined analysis file extension
- //in addition to CDP_SOUND_EXT ...
- //RWD98 now declared static at top of file
- /*RWD for DevCPp*/
- #ifndef _MAX_PATH
- #define _MAX_PATH (255)
- #endif
- static enum sndfiletype
- gettypefromname98(const char *path)
- {
- #ifdef NOTDEF
- char *eos = &path[strlen(path)]; /* points to the null byte */
- char *lastsl = strrchr(path, PATH_SEP);
- #else
- //RWD98: use hackable local copy of path, to check for WIN32 shortcut
- //this bit general, though
- char *eos, *lastsl;
- char copypath[_MAX_PATH];
- int len;
- copypath[0] = '\0';
- strcpy(copypath,path);
- len = strlen(copypath);
- eos = ©path[len];
- lastsl = strrchr(copypath,PATH_SEP);
- #endif
- // if(lastsl == 0) //RWD 2022 this fails if path is in current directory, no separator present
- //abort();
- // return unknown_wave; //RWD.1.99
- #ifdef _WIN32
- //it it a shortcut?
- if(_stricmp(eos-4, ".lnk")==0) {
- copypath[len-4] = '\0'; //cut away link extension
- eos -= 4; //step past the ext, we should be left with a kosher sfilename
- }
- #endif
- if(eos-4 > lastsl && _stricmp(eos-4, ".wav") == 0)
- return riffwav;
- else if(eos-4 > lastsl && _stricmp(eos-4, ".aif") == 0)
- return eaaiff;
- else if(eos-5 > lastsl && _stricmp(eos-5, ".aiff") == 0)
- return eaaiff;
- //Recognize AIF-C files: use separate sndfiletype for this?
- else if(eos-4 > lastsl && _stricmp(eos-4,".afc") == 0)
- return aiffc;
- else if(eos-4 > lastsl && _stricmp(eos-4,".aic") == 0)
- return aiffc;
- else if(eos-5 > lastsl && _stricmp(eos-5,".aifc") == 0)
- return aiffc;
- /* FILE_AMB_SUPPORT */
- else if(eos-4 > lastsl && _stricmp(eos-4, ".amb") == 0)
- return riffwav;
- else if(eos-5 > lastsl && _stricmp(eos-5, ".ambi") == 0) //RWD April 2006 was -4 !
- return riffwav;
- else if(eos-5 > lastsl && _stricmp(eos-5, ".wxyz") == 0)
- return riffwav;
- //CDP97: recognise .ana as signifying analysis file - find out later whether wav or aiff
- /* 4:2001 added revised extensions for and evl; lose fmt and env in time */
- else if(_stricmp(eos-4, ".ana") == 0 //analysis file
- || _stricmp(eos-4,".fmt") == 0 //formant file
- || _stricmp(eos-4,".for") == 0
- || _stricmp(eos-4,".frq") == 0 // pitch file
- || _stricmp(eos-4,".env") == 0 // binary envelope
- || _stricmp(eos-4,".evl") == 0
- || _stricmp(eos-4,".trn") == 0 ) // transposition file
- return cdpfile;
- #ifdef ENABLE_PVX
- else if(_stricmp(eos-4,".pvx") == 0 ) //PVOCEX analysis file
- return pvxfile;
- #endif
- return unknown_wave;
- }
- //if a cdpfile - what format is it?
- //RWD TODO: rewrite this with error retval, or at least add sferrstr message if bad seek
- /* RWD NB: would need to drill further into header to discover a pvx file - maybe a "findGuid" function? */
- /* but currently this leaves the file open for further parsing, currently pvx handled separately */
- static enum sndfiletype
- gettypefromfile(struct sf_file *f)
- {
- DWORD tag1,tag2,size;
- enum sndfiletype type = unknown_wave;
- if(read_dw_msf(&tag1, f) || read_dw_lsf(&size, f) || read_dw_msf(&tag2,f)) {
- #if defined _WIN32
- if(SetFilePointer(f->fileno,0,NULL,FILE_BEGIN)==0xFFFFFFFF)
- #else
- if(fseek(f->fileno,0,SEEK_SET) < 0)
- #endif
- return unknown_wave;
- }
- else if(tag1 == TAG('R','I','F','F') && tag2 == TAG('W','A','V','E')){
- type = riffwav;
- }
- else if(tag1 == TAG('F','O','R','M') && tag2 == TAG('A','I','F','F')){
- type = eaaiff;
- }
- //RWD.1.99 support aifc files as well
- else if(tag1 == TAG('F','O','R','M') && tag2 == TAG('A','I','F','C')){
- type = aiffc;
- }
- #if defined _WIN32
- if(SetFilePointer(f->fileno,0,NULL,FILE_BEGIN)==0xFFFFFFFF)
- #else
- if(fseek(f->fileno,0,SEEK_SET) < 0)
- #endif
- return unknown_wave;
- return type;
- }
- //RWD.6.98 when tested, add shortcuts code...
- static char *
- mksfpath(const char *name)
- {
- char *errormsg;
- char *path = _fullpath(NULL, name, 0);
- enum sndfiletype filetype = unknown_wave; //RWD 2015
- if(path == NULL) {
- rsferrno = ESFBADPARAM;
- rsferrstr = "can't find full path for soundfile - bad drive?";
- //#ifdef unix
- // printf("realpath failed:errno = %d:%s\n",errno,strerror(errno));
- //#endif
- return NULL;
- }
- #ifdef _WIN32
- //if its a shortcut, strip off the link extension: sfopen will try normal open first
- {
- int len;
- char *eos;
- len = strlen(path);
- eos = &path[len-4];
- if(_stricmp(eos,".lnk")==0)
- path[len-4] = '\0';
- }
- #endif
- /* RWD March 2014 make this optional! */
- filetype = gettypefromname98(path);
- if( filetype == unknown_wave) {
- char *newpath;
- char *ext;
- char *ext_default = "wav";
- // RWD MAR 2015 we may have unset CDP_SOUND_EXT, but not removed it completely!
- if((ext = getenv("CDP_SOUND_EXT")) == NULL || strlen(ext) == 0 ) {
- //rsferrno = ESFBADPARAM;
- //rsferrstr = "unknown sound file type - extension not set";
- //free(path);
- //return NULL;
- ext = ext_default;
- }
- if(_stricmp(ext, "wav") != 0
- &&_stricmp(ext, "aif") != 0
- &&_stricmp(ext, "aiff") != 0
- &&_stricmp(ext,"afc") != 0 //Apple...
- &&_stricmp(ext,"aic") != 0 //Csound uses this form
- &&_stricmp(ext,"aifc") !=0) {
- rsferrno = ESFBADPARAM;
- rsferrstr = "unknown sound file type - bad CDP_SOUND_EXT setting";
- free(path);
- return NULL;
- }
- if((newpath = (char *) malloc(strlen(path) + strlen(ext) + 2)) == 0) {
- rsferrno = ESFNOMEM;
- rsferrstr = "can't get memory for full path of soundfile";
- free(path);
- return NULL;
- }
- strcpy(newpath, path);
- strcat(newpath, ".");
- strcat(newpath, ext);
- free(path);
- path = newpath;
- }
- if((errormsg = legalfilename(path)) != 0) {
- rsferrno = ESFBADPARAM;
- rsferrstr = errormsg;
- free(path);
- return NULL;
- }
- return path;
- }
- /*
- * public sf routines
- */
- //RWD.6.98 TODO when tested, add all the file-sharing code
- // best to #ifdef the revised function in as a block...
- /* RWD TOD 2022: get rid of all the ifdefs, make separate whole functions */
- #if 0
- int
- sfopen(const char *name)
- {
- int i, rc;
- struct sf_file *f;
- char *sfpath;
- #if defined _WIN32
- DWORD access = GENERIC_WRITE | GENERIC_READ; //assumeed for first open (eg for maxsamp...)
- //seems I need to set write sharing so some other process can write...
- DWORD sharing = FILE_SHARE_READ; //for first open
- #else
- char *faccess = "r+";
- #endif
- //#ifdef _WIN32
- char newpath[_MAX_PATH];
- newpath[0] = '\0';
- //#endif
- if((sfpath = mksfpath(name)) == NULL)
- return -1;
- if((i = allocsffile(sfpath)) < 0)
- return -1;
- f = sf_files[i];
- //#ifdef NOTDEF
- //this may not be needed after all: can't really display a file while is is being written to...
- if(f->refcnt > 1) {
- # if defined _WIN32
- access = GENERIC_READ;
- sharing = FILE_SHARE_WRITE | FILE_SHARE_READ; //repeat opens MUST allow first open to write!
- # else
- //faccess = "r"; /*RWD 2010 allow this ?? */
- rsferrno = ESFNOTOPEN;
- rsferrstr = "Can't open file more than once - yet!";
- freesffile(i);
- return -1;
- # endif
- }
- //#endif
- f->readonly = 0;
- #ifdef _WIN32
- f->is_shortcut = 0;
- #endif
- //first, try normal open as rd/wr
- #if defined _WIN32
- if((f->fileno = CreateFile(f->filename,access,sharing,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL)) == INVALID_HANDLE_VALUE)
- #else
- if((f->fileno = fopen(f->filename, faccess)) == NULL)
- #endif
- {
- #if defined _WIN32
- DWORD w_errno = GetLastError();
- #endif
- rsferrno = ESFNOTFOUND;
-
- #if defined _WIN32
- if(w_errno != ERROR_FILE_NOT_FOUND){
- #else
- if(errno != ENOENT){ //won't exist if its actually a shortcut
- #endif
-
- #if defined _WIN32
- if(w_errno == ERROR_INVALID_NAME) {
- #else
- if(errno == EINVAL) {
- #endif
- rsferrstr = "Illegal filename";
- freesffile(i);
- return -1;
- }
- #if defined _WIN32
- if(w_errno != ERROR_ACCESS_DENIED) {
- #else
- if(errno != EACCES) {
- #endif
- rsferrstr = "SFile not found";
- freesffile(i);
- return -1;
- }
- }
- }
- /* block below is ONLY for Windows */
- #ifdef _WIN32
- //try a shortcut to rd/wr file...
- if(f->fileno == INVALID_HANDLE_VALUE){
- if(
- (CDP_COM_READY) &&
- (getAliasName(f->filename,newpath)) &&
- //# ifdef CDP99
- ((f->fileno = CreateFile(newpath,access,sharing,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL)) == INVALID_HANDLE_VALUE)
- //# else
- // ((f->fileno = open(newpath, _O_BINARY|_O_RDWR) ) < 0)
- //# endif
- ) {
- //good link, but still no open...
- //# ifdef CDP99
- DWORD w_errno = GetLastError();
- rsferrno = ESFNOTFOUND;
- if(w_errno == ERROR_INVALID_NAME) {
- //# else
- // rsferrno = ESFNOTFOUND;
- // if(errno == EINVAL) {
- //# endif
- rsferrstr = "Illegal filename";
- freesffile(i);
- return -1;
- }
- //# ifdef CDP99
- if(w_errno != ERROR_ACCESS_DENIED) {
- //# else
- // if(errno != EACCES) {
- //# endif
- rsferrstr = "SFile not found";
- freesffile(i);
- return -1;
- }
- }
- }
- #endif
- /* "normal" file open code here */
- //must be rdonly, try normal open or shortcut
- #if defined _WIN32
- if(f->fileno== INVALID_HANDLE_VALUE){
- #else
- if(f->fileno==NULL){
- #endif
-
- #ifdef _WIN32
- if(
- ((f->fileno = CreateFile(f->filename, GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_READONLY,NULL)) == INVALID_HANDLE_VALUE)
- && (!((CDP_COM_READY) || (getAliasName(f->filename,newpath)))
-
- || ((f->fileno = CreateFile(newpath, GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_READONLY,NULL)) == INVALID_HANDLE_VALUE)
- )
- #else
- if(
- ((f->fileno = fopen(f->filename, "r")) == NULL)
-
- )
- #endif
- {
- rsferrstr = "SFile not found";
- freesffile(i);
- return -1;
- }
- f->readonly = 1;
- }
- #ifdef _WIN32
- if(strlen(newpath) >0) {
- f->filename[0] = '\0';
- f->is_shortcut = 1;
- strcpy(f->filename,newpath); //filename will be freed eventually; don't copy pointers
- }
- #endif
- switch(f->filetype = gettypefromfile(f)) {
- case riffwav:
- rc = rdwavhdr(f);
- break;
- case eaaiff:
- rc = rdaiffhdr(f);
- break;
- case aiffc:
- rc = rdaifchdr(f);
- break;
- default:
- rsferrno = ESFNOSTYPE;
- rsferrstr = "Internal error: can't find file type";
- rc = 1;
- }
- if(rc) {
- freesffile(i);
- return -1;
- }
- f->infochanged = 0;
- f->todelete = 0;
- f->sizerequested = ES_EXIST;
- f->curpos = 0;
- return i+SFDBASE;
- }
- #endif
- #ifdef ENABLE_PVX
- /* return -1 for error in fd, 0 for false (i.e. is sfile or .ana file), 1 for true */
- int sf_ispvx(int sfd)
- {
- struct sf_file *f;
-
- if((f = findfile(sfd)) == 0)
- return -1;
- return (f->filetype == pvxfile);
- }
-
- /* pvx file id can be 0, so that can't be used to flag error */
- int get_pvxfd(int sfd ,PVOCDATA *pvxdata ){
- struct sf_file *f;
- int rc = -1;
- if((f = findfile(sfd)) == 0)
- return rc;
- else if((f->filetype == pvxfile) && (f->pvxprops != NULL)) {
- rc = f->pvxfileno;
- if(pvxdata != NULL) {
- //memcpy((char*) pvxdata,(char*) &f->pvxprops,sizeof(PVOCDATA));
- pvxdata->wWordFormat = f->pvxprops->wWordFormat;
- pvxdata->wAnalFormat = f->pvxprops->wAnalFormat;
- pvxdata->wSourceFormat = f->pvxprops->wSourceFormat;
- pvxdata->wWindowType = f->pvxprops->wWindowType;
- pvxdata->nAnalysisBins = f->pvxprops->nAnalysisBins;
- pvxdata->dwWinlen = f->pvxprops->dwWinlen;
- pvxdata->dwOverlap = f->pvxprops->dwOverlap;
- pvxdata->dwFrameAlign = f->pvxprops->dwFrameAlign;
- pvxdata->fAnalysisRate = f->pvxprops->fAnalysisRate;
- pvxdata->fWindowParam = f->pvxprops->fWindowParam;
- }
- }
- return rc;
- }
- // this needs to be declared in sffuncs.h - accessible by snd.c, but not durectly to app code
- /* currently NOTUSED, ditto snd_getpvxfno in snd.c */
- int getpvxfno(int sfd){
- struct sf_file *f;
- int rc = 0;
- if((f = findfile(sfd)) == 0)
- rc = -1;
- else if(f->pvxprops == NULL) //bad call to getpvxfno
- rc = -1;
- else
- rc = f->pvxfileno;
- return rc;
- }
- #endif
- //RWD.9.98 new version to control access
- int
- sfopenEx(const char *name, unsigned int access)
- {
- int i, rc;
- struct sf_file *f;
- char *sfpath;
- char newpath[_MAX_PATH];
- newpath[0] = '\0';
- if((sfpath = mksfpath(name)) == NULL)
- return -1;
- if((i = allocsffile(sfpath)) < 0)
- return -1;
- #ifdef ENABLE_PVX
- # ifdef _DEBUG
- //fprintf(stderr,"sfopenEx: opened in sf_sfiles[%d]\n",i);
- # endif
- f = sf_files[i];
- f->readonly = 0;
- f->is_shortcut = 0;
- #endif
-
- #ifdef ENABLE_PVX
- // RWD just cheat for now, until it's all working...
- if(gettypefromname98(name) == pvxfile){
- int rc = 0;
- PVOCDATA pvxdata;
- WAVEFORMATEX wftx;
- // setup property block
- # ifdef _DEBUG
- assert(f->pvxprops == NULL);
- assert(f->curpropsize == 0);
- assert(f->props == NULL);
- # endif
- f->filetype = pvxfile;
- f->pvxprops = calloc(1,sizeof(PVOCDATA));
- rc = pvoc_openfile(name,&pvxdata, &wftx);
- if(rc >= 0) {
- memcpy(f->pvxprops,&pvxdata, sizeof(PVOCDATA));
- memcpy(&(f->fmtchunkEx.Format), &wftx, sizeof(WAVEFORMATEX));
- /* in PVX, Format contains details of the source soundfile for this analysis file (original sampsize etc
- * this has to be converted into the relevant SFPROPS fields,
- * and then we have to reconvert Format into what would be obtained from a CDP .ana file.
- * e.g. must be 32bit floats, srate is (int) analysis rate
- */
- //TODO: get datachunk info from header to complete fields in f...which will help dirsf show good numbers.
- f->datachunksize = pvoc_getdatasize_bytes(rc);
-
- if(pvx_createprops(f) < 0){
- free(f->pvxprops);
- f->pvxprops = NULL;
- return -1;
- }
- # ifdef _DEBUG
- // fprintf(stderr,"sfopenEx: opened pvx file %s - chans = %d\n", name, f->fmtchunkEx.Format.nChannels);
- # endif
- f->fmtchunkEx.Format.nSamplesPerSec = (int) pvxdata.fAnalysisRate;
- f->fmtchunkEx.Format.nChannels = pvxdata.nAnalysisBins * 2;
- f->fmtchunkEx.Format.wBitsPerSample = 32;
- f->fmtchunkEx.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
- f->fmtchunkEx.Format.nBlockAlign = f->fmtchunkEx.Format.nChannels * sizeof(float);
- f->fmtchunkEx.Format.nAvgBytesPerSec =f->fmtchunkEx.Format.nBlockAlign * f->fmtchunkEx.Format.nSamplesPerSec;
- # ifdef _DEBUG
- // fprintf(stderr,"sfopenEx: opened pvx file %s - chans = %d\n", name, f->fmtchunkEx.Format.nChannels);
- # endif
- f->min_header = SFILE_ANAL; // RWD: may not be needed in this case...?
- f->pvxfileno = rc;
- f->infochanged = 0;
- f->todelete = 0;
- f->sizerequested = ES_EXIST;
- f->curpos = 0;
- //RWD: can't decide whether to fill in datachunksize too for full sf mimicry ...
- // don't really want snd funcs to depend on that if it can be avoided
-
- // if(access == CDP_OPEN_RDONLY)
- f->readonly = 1;
- return i + SFDBASE; // should be fine, we will always check for pvx file
- }
- else {
- # ifdef _DEBUG
- // fprintf(stderr, "sfopenEx: failed to open pvocex file %s\n", name);
- # endif
- free(f->pvxprops);
- f->pvxprops = NULL;
- rsferrstr = "PVX file not found";
- freesffile(i);
- return -1;
- }
- }
- #endif
-
- /* non-PVX from here */
- if(access == CDP_OPEN_RDONLY){
- #if defined _WIN32
- if(((f->fileno = CreateFile(f->filename, GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_READONLY,NULL)) == INVALID_HANDLE_VALUE)
- #else
- if(((f->fileno = fopen(f->filename, "r")) == NULL)
- #endif
- && ((!CDP_COM_READY)
- || (!getAliasName(f->filename,newpath))
- #if defined _WIN32
- || ((f->fileno = CreateFile(newpath, GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_READONLY,NULL)) == INVALID_HANDLE_VALUE)
- #else
- || ((f->fileno = fopen(newpath, "r") ) == NULL)
- #endif
- )){
- rsferrstr = "SFile not found";
- freesffile(i);
- return -1;
- }
- f->readonly = 1;
- }
- else {
- // normal open as rd/wr
- #if defined _WIN32
- DWORD w_errno;
- if((f->fileno = CreateFile(f->filename, GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_READONLY,NULL)) == INVALID_HANDLE_VALUE) {
- #else
- if((f->fileno = fopen(f->filename, "r+")) == NULL ) {
- #endif
- rsferrno = ESFNOTFOUND;
- #if defined _WIN32
- w_errno= GetLastError();
- if(w_errno != ERROR_FILE_NOT_FOUND){
- #else
- if(errno != ENOENT){ //won't exist if its actually a shortcut
- #endif
- #if defined _WIN32
- if(w_errno == ERROR_INVALID_NAME) {
- #else
- if(errno == EINVAL) {
- #endif
- rsferrstr = "Illegal filename";
- freesffile(i);
- return -1;
- }
- #if defined _WIN32
- if(w_errno != ERROR_ACCESS_DENIED) {
- #else
- if(errno != EACCES) {
- #endif
- rsferrstr = "SFile not found";
- freesffile(i);
- return -1;
- }
- }
- }
- //try a shortcut to rd/wr file...
- # ifdef _WIN32
- if(f->fileno == INVALID_HANDLE_VALUE){
- # else
- if(f->fileno == NULL){
- # endif
- if(
- (CDP_COM_READY) &&
- (getAliasName(f->filename,newpath)) &&
- #if defined _WIN32
- ((f->fileno = CreateFile(newpath, GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_READONLY,NULL)) == INVALID_HANDLE_VALUE)
- #else
- ((f->fileno = fopen(newpath, "r+") ) == NULL)
- #endif
- ) {
- //good link, but still no open...
- rsferrno = ESFNOTFOUND;
- #if defined _WIN32
- if(w_errno == ERROR_INVALID_NAME) {
- #else
- if(errno == EINVAL) {
- #endif
- rsferrstr = "Illegal filename";
- freesffile(i);
- return -1;
- }
- #if defined _WIN32
- if(w_errno != ERROR_ACCESS_DENIED) {
- #else
- if(errno != EACCES) {
- #endif
- rsferrstr = "SFile not found";
- freesffile(i);
- return -1;
- }
- }
- }
- #if defined _WIN32
- if(f->fileno== INVALID_HANDLE_VALUE){
- #else
- if(f->fileno == NULL){
- #endif
- rsferrstr = "SFile not found";
- freesffile(i);
- return -1;
- }
- }
- #ifdef _WIN32
- if(strlen(newpath) >0) {
- f->filename[0] = '\0';
- f->is_shortcut = 1;
- strcpy(f->filename,newpath); //filename will be freed eventually; don't copy pointers
- }
- #endif
- switch(f->filetype = gettypefromfile(f)) {
- case riffwav:
- rc = rdwavhdr(f);
- break;
- case eaaiff:
- rc = rdaiffhdr(f);
- break;
- case aiffc:
- rc = rdaifchdr(f);
- break;
- default:
- rsferrno = ESFNOSTYPE;
- rsferrstr = "Internal error: can't find file type";
- rc = 1;
- }
- if(rc) {
- freesffile(i);
- return -1;
- }
- f->infochanged = 0;
- f->todelete = 0;
- f->sizerequested = ES_EXIST;
- f->curpos = 0;
- return i+SFDBASE;
- }
- static struct sf_file *
- findfile(int sfd)
- {
- sfd -= SFDBASE;
- if(sfd < 0 || sfd >= SF_MAXFILES || sf_files[sfd] == 0) {
- rsferrno = ESFNOTOPEN;
- rsferrstr = "soundfile descriptor does not refer to an open soundfile";
- return 0;
- }
- return sf_files[sfd];
- }
- static int
- comparewithlist(const char *list, const char *name)
- {
- size_t len = strlen(name);
- for(;;) {
- if(_strnicmp(list, name, len) == 0
- &&(list[len] == '\0' || list[len] == ','))
- return 1;
- if((list = strchr(list, ',')) == 0)
- break;
- list++;
- }
- return 0;
- }
- /* RWD note: used only for create functions */
- #if defined _WIN32
- static HANDLE doopen(const char *name, const char *origname,cdp_create_mode mode)
- {
- char *ovrflg;
- HANDLE rc;
- DWORD access,sharing,attrib,w_errno;
- access = GENERIC_READ | GENERIC_WRITE;
- sharing = FILE_SHARE_READ;
- attrib = FILE_ATTRIBUTE_NORMAL;
- if(mode==CDP_CREATE_TEMPORARY){
- sharing = 0;
- attrib = FILE_ATTRIBUTE_TEMPORARY
- | FILE_ATTRIBUTE_HIDDEN
- | FILE_FLAG_DELETE_ON_CLOSE;
- }
- if(mode==CDP_CREATE_RDONLY)
- attrib = FILE_ATTRIBUTE_READONLY;
- if((rc = CreateFile(name, access,sharing,NULL,CREATE_NEW,attrib,NULL)) != INVALID_HANDLE_VALUE)
- return rc;
- w_errno = GetLastError();
- if(!(w_errno == ERROR_FILE_EXISTS || w_errno==ERROR_ALREADY_EXISTS))
- return rc;
- if(mode==CDP_CREATE_NORMAL){
- if((ovrflg = getenv("CDP_OVERWRITE_FILE")) == 0)
- return rc;
- if(strcmp(ovrflg, "*") != 0
- &&!comparewithlist(ovrflg, origname))
- return rc;
- return CreateFile(name, access,sharing,NULL,CREATE_ALWAYS,attrib,NULL);
- }
- else
- return rc;
- }
- #else
- static FILE* doopen(const char *name, const char *origname,cdp_create_mode mode)
- {
- char *ovrflg;
- FILE* fp = NULL;
- //RWD set modeflags here to allow setting a temporary file in CDP97
- //int exclmode,truncmode;
- //exclmode = (_O_BINARY|_O_RDWR|_O_CREAT|_O_EXCL );
- //truncmode = (_O_BINARY|_O_RDWR|_O_TRUNC);
- char *fmode = "w+x";
- #ifdef _WIN32
- if(mode==CDP_CREATE_TEMPORARY){
- exclmode |= /*_O_SHORT_LIVED*/_O_TEMPORARY; //create as temporary, if poss no flush to disk
- }
- #else
- /* TODO: replace with mkstemp, maybe use origname as part of template? */
- /* RWD MAR 2015, need to eliminate call to tmpnam,
- * without having to alloc new memory for modifiable name for mkstemp() */
- /* only the old GUI programs (GrainMill) ask for a temporary filename, anyway... */
- //if(mode==CDP_CREATE_TEMPORARY)
- // name = tmpnam(NULL);
- #endif
- if(mode==CDP_CREATE_RDONLY){
- //exclmode = (_O_BINARY|_O_RDONLY|_O_CREAT|_O_EXCL );
- //truncmode = (_O_BINARY|_O_RDONLY|_O_TRUNC);
- fmode = "r+x";
- }
- if((fp = fopen(name,fmode ))!= NULL)
- return fp;
- if(errno != EEXIST)
- return fp;
- if((ovrflg = getenv("CDP_OVERWRITE_FILE")) == 0)
- return fp;
- if(strcmp(ovrflg, "*") != 0
- &&!comparewithlist(ovrflg, origname))
- return fp;
- // allow overwriting (I hope...) */
- return fopen(name,"w+");
- }
- #endif
- //RWD 2022 removed old sfcreat()
- static int file_exists(const char * fname)
- {
- int rc = 0;
- struct stat buffer;
- rc = stat(fname,&buffer);
- if(rc == 0){
- errno = EEXIST;
- rsferrstr = "Can't create SFile, already exists";
- return 1;
- }
- else
- return 0;
- }
- /********* SFSY98 extension: supply format info for streaming, etc *******/
- //RWD.6.99 supports all new legal formats, except WAVE_EX (use sfcreat_ex)
- //RWD.1.99 added mode arg to create temporary file in Current Directory
- /*RWD 2007: change size params to __int64 */
- int sfcreat_formatted(const char *name, __int64 size, __int64 *outsize,int channels,
- int srate, int stype,cdp_create_mode mode) {
- int i, rc;
- struct sf_file *f;
- char *sfpath;
- /* RWD March 2014 */
- char *ext_default = "wav";
- /*RWD 2007 */
- __int64 freespace = getdrivefreespace(name) - LEAVESPACE;
- if((sfpath = mksfpath(name)) == NULL)
- return -1;
- if((i = allocsffile(sfpath)) < 0)
- return -1;
- f = sf_files[i];
-
- #ifdef ENABLE_PVX
- /* a split file creation: create partly-complete header, to be filled in later by host.
- * we receive channels (which sets FFTsize for pvx).
- * currently, pvsys create func sets winlen (etc) to default values if arg = 0 : might need to redesign this!
- * horrible suspicion progs ask for pvoc srate = int analysis rate.
- * Not sure how to use the size args.
- * so we will ignore them unless and until this creates a problem!
- */
- // CDP code covers this, but pvocsys doesn't
- if(file_exists(name)){
- #ifdef _DEBUG
- fprintf(stderr,"file exists - can't create\n");
- #endif
- freesffile(i);
- return -1;
- }
- if(gettypefromname98(name) == pvxfile){
- //need to get source (CDP) stype into file header
- int pv_stype = STYPE_16;
- int rc = 0;
-
- switch(stype) {
- case INT2424:
- case INT2024:
- pv_stype = STYPE_24;
- break;
- case INT2432:
- case INT_32:
- pv_stype = STYPE_32;
- break;
- case FLOAT32:
- pv_stype = STYPE_IEEE_FLOAT;
- break;
- default:
- break;
- }
-
- f->filetype = pvxfile;
- // setup property block
- # ifdef _DEBUG
- assert(f->pvxprops == NULL);
- assert(f->curpropsize == 0);
- assert(f->props == NULL);
- # endif
- f->proplim = 2000; /* bytes; arbitrary. each putprop call checks this */
- f->pvxprops = calloc(1,sizeof(PVOCDATA));
- // init what we can, rely on file close to complete header via SFPROPS etc
- rc = pvoc_createfile(name,channels - 2,0,1,PVOC_AMP_FREQ,0,pv_stype, PVOC_HANN,0.0,NULL,0);
- if(rc < 0){
- # ifdef _DEBUG
- fprintf(stderr,"sfsys: pvoc_createfile failed: %s\n", pvoc_errorstr());
- # endif
- return -1;
- }
- else {
- # ifdef _DEBUG
- // fprintf(stderr,"pvoc_createfile succeeded i= %d,rc = %d\n",i,rc);
- # endif
- }
- f->pvxfileno = rc;
- if(!pvoc_getpvxprops(f->pvxfileno,f->pvxprops)){
- fprintf(stderr,"sfsys: error from pvoc_getpvxprops\n");
- }
- pvoc_set_needsupdate(f->pvxfileno);
- f->readonly = 0; /* NB: contols if sfputprop() etc succeeds */
- # ifdef _DEBUG
- assert(f->pvxprops->nAnalysisBins > 0);
- # endif
- return i+SFDBASE;
- }
- #endif
- // from here: just normal CDP files
-
- //RWD: this is OK, as it tells us we cannot CREATE more than one file of the same name, or one already opened
- if(f->refcnt > 1) {
- rsferrno = ESFNOTOPEN;
- rsferrstr = "Can't open file more than once - yet!";
- freesffile(i);
- return -1;
- }
- #if defined _WIN32
- if((f->fileno = doopen(f->filename, name,mode)) == INVALID_HANDLE_VALUE) {
- DWORD w_errno = GetLastError();
- #else
- if((f->fileno = doopen(f->filename, name,mode)) == NULL) {
- #endif
- #if defined _WIN32
- switch(w_errno) {
- case ERROR_INVALID_NAME:
- rsferrno = ESFNOTOPEN;
- rsferrstr = "Can't create SFile, Illegal filename";
- break;
- case ERROR_FILE_EXISTS:
- case ERROR_ALREADY_EXISTS:
- rsferrno = ESFDUPFNAME;
- rsferrstr = "Can't create SFile, already exists";
- break;
- case ERROR_ACCESS_DENIED:
- rsferrno = ESFNOTOPEN;
- rsferrstr = "Can't create SFile, permission denied";
- break;
- default:
- rsferrno = ESFNOTOPEN;
- rsferrstr = "Can't create SFile, Internal error";
- }
- #else
- switch(errno) {
- case EINVAL:
- rsferrno = ESFNOTOPEN;
- rsferrstr = "Can't create SFile, Illegal filename";
- break;
- case EEXIST:
- rsferrno = ESFDUPFNAME;
- rsferrstr = "Can't create SFile, already exists";
- break;
- case EACCES:
- rsferrno = ESFNOTOPEN;
- rsferrstr = "Can't create SFile, permission denied";
- break;
- default:
- rsferrno = ESFNOTOPEN;
- rsferrstr = "Can't create SFile, Internal error";
- }
- #endif
- freesffile(i);
- return -1;
- }
- if(size < 0)
- f->sizerequested = freespace;
- else if(size >= freespace) {
- rsferrno = ESFNOSPACE;
- rsferrstr = "Not enough space on Disk to create sound file";
- //RWD.7.99
- #if defined _WIN32
- CloseHandle(f->fileno);
- DeleteFile(f->filename);
- #else
- fclose(f->fileno);
- remove(f->filename);
- #endif
- freesffile(i);
- return -1;
- } else
- f->sizerequested = /*size&~1*/ size; /* RWD NOV 2001 NO ROUNDING! We have 24bit samples now! */
- f->readonly = 0;
- f->header_set = 0;
- ///RWD.6.5.99 prepare peak storage
- f->peaks = (CHPEAK *) calloc(channels, sizeof(CHPEAK));
- if(f->peaks==NULL){
- rsferrno = ESFNOMEM;
- rsferrstr = "No memory to create peak data storage";
- //RWD.7.99
- #if defined _WIN32
- CloseHandle(f->fileno);
- DeleteFile(f->filename);
- #else
- fclose(f->fileno);
- remove(f->filename);
- #endif
- freesffile(i);
- return -1;
- }
- switch(f->filetype = gettypefromname98(f->filename)) {
- char *ext;
- /******* RWD.7.98 all we have to do to write a requested format is to fill in the data in f->fmtchunk
- ******* and get wrwavhdr() to read this in! *****/
- case riffwav:
- rc = wrwavhdr98(f,channels,srate,stype);
- break;
- case eaaiff:
- //make sure AIFF format is legal!
- if(stype==SAMP_2432){
- //reject here, as can't tell caller
- rsferrno = ESFBADPARAM;
- rsferrstr = "requested sample type illegal for AIFF files";
- return -1;
- }
- if(stype==SAMP_FLOAT){
- //we now require AIFC for float formats
- f->filetype = aiffc;
- rc = wraifchdr(f,channels,srate,stype);
- }
- else
- rc = wraiffhdr98(f,channels,srate,stype);
- break;
- //RWD temporary
- case aiffc:
- //make sure AIFF format is legal!
- if(stype==SAMP_2432){
- //reject here, as can't tell caller
- rsferrno = ESFBADPARAM;
- rsferrstr = "requested sample type illegal for AIFF files";
- return -1;
- }
- rc = wraifchdr(f,channels,srate,stype);
- break;
- case cdpfile:
- /* RWD MAR 2015 as above */
- if((ext = getenv("CDP_SOUND_EXT")) == NULL || strlen(ext) == 0) {
- ext = ext_default;
- }
- f->min_header = SFILE_ANAL; /*RWD Nov 2009: but we don't want PEAK, CUE for analysis files! */
- if(f->peaks){
- free(f->peaks);
- f->peaks = NULL;
- }
- if(_stricmp(ext, "wav") == 0){
- rc = wrwavhdr98(f,channels,srate,stype); /*RWD 5:2003*/
- f->filetype = riffwav;
- }
- else if(_stricmp(ext, "aif") == 0 || _stricmp(ext, "aiff") == 0){
- if(stype==SAMP_FLOAT){
- //we now require AIFC for float formats
- f->filetype = aiffc;
- rc = wraifchdr(f,channels,srate,stype);
- }
- else{
- rc=wraiffhdr98(f,channels,srate,stype);
- f->filetype= eaaiff;
- }
- }
- //RWD.1.99 temporary
- else if(_stricmp(ext, "aic") == 0
- || _stricmp(ext, "afc") == 0
- || _stricmp(ext, "aifc") == 0){
- rc=wraifchdr(f,channels,srate,stype);
- f->filetype= aiffc;
- }
- else {
- rsferrno = ESFBADPARAM;
- rsferrstr = "unknown sound file type - bad CDP_SOUND_EXT setting";
- //RWD.7.99
- #if defined _WIN32
- CloseHandle(f->fileno);
- DeleteFile(f->filename);
- #else
- fclose(f->fileno);
- remove(f->filename);
- #endif
- return -1;
- }
- break;
- default:
- rsferrno = ESFNOSTYPE;
- rsferrstr = "Internal error: can't find filetype";
- rc = 1;
- }
- if(rc) {
- //RWD.7.99
- #if defined _WIN32
- CloseHandle(f->fileno);
- DeleteFile(f->filename);
- #else
- fclose(f->fileno);
- remove(f->filename);
- #endif
- freesffile(i);
- return -1;
- }
- f->datachunksize = 0;
- f->infochanged = 0;
- f->todelete = 0;
- if(outsize != 0)
- *outsize = (unsigned int) f->sizerequested;
- f->curpos = 0;
- return i+SFDBASE;
- }
- //special version for wave-ex
- //props is both in and out
- int sfcreat_ex(const char *name, __int64 size, __int64 *outsize,SFPROPS *props,int min_header,cdp_create_mode mode)
- {
- int i, rc;
- int stype = -1;
- struct sf_file *f;
- char *sfpath;
- char *ext_default = "wav"; /* RWD March 2014 */
- unsigned long freespace = getdrivefreespace(name) - LEAVESPACE;
- if((sfpath = mksfpath(name)) == NULL)
- return -1;
- if(min_header < SFILE_MINIMUM || min_header > SFILE_CDP){
- rsferrno = ESFBADPARAM;
- rsferrstr = "bad min_header spec";
- return -1;
- }
- if((i = allocsffile(sfpath)) < 0)
- return -1;
- f = sf_files[i];
- //RWD: this is OK, as it tells us we cannot CREATE more than one file of the same name, or one already opened
- if(f->refcnt > 1) {
- rsferrno = ESFNOTOPEN;
- rsferrstr = "Can't open file more than once - yet!";
- freesffile(i);
- return -1;
- }
- //can only minimise header for wavefile!
- if(props->type == wt_wave)
- f->min_header = min_header;
- //reject analysis formats if not floatsams
- else{ // must be wt_analysis
- if(props->samptype != FLOAT32){
- rsferrno = ESFBADPARAM;
- rsferrstr = "Analysis data must be floats";
- freesffile(i);
- return -1;
- }
- }
- switch(props->samptype){
- case (SHORT16):
- stype = SAMP_SHORT;
- break;
- case(FLOAT32):
- stype = SAMP_FLOAT;
- break;
- case(INT_32):
- stype = SAMP_LONG;
- break;
- case(INT2424):
- stype = SAMP_2424;
- break;
- case(INT2024):
- stype = SAMP_2024;
- break;
- case(INT2432):
- stype = SAMP_2432;
- break;
- default:
- rsferrno = ESFBADPARAM;
- rsferrstr = "unsupported sample type"; //add speaker mask stuff ere long, if WAVE_EX
- freesffile(i);
- return -1;
- break;
- }
- #if defined _WIN32
- if((f->fileno = doopen(f->filename, name,mode)) == INVALID_HANDLE_VALUE) {
- DWORD w_errno = GetLastError();
- #else
- if((f->fileno = doopen(f->filename, name,mode)) == NULL) {
- #endif
- #if defined _WIN32
- switch(w_errno) {
- case ERROR_INVALID_NAME:
- rsferrno = ESFNOTOPEN;
- rsferrstr = "Can't create SFile, Illegal filename";
- break;
- case ERROR_FILE_EXISTS:
- case ERROR_ALREADY_EXISTS:
- rsferrno = ESFDUPFNAME;
- rsferrstr = "Can't create SFile, already exists";
- break;
- case ERROR_ACCESS_DENIED:
- rsferrno = ESFNOTOPEN;
- rsferrstr = "Can't create SFile, permission denied";
- break;
- default:
- rsferrno = ESFNOTOPEN;
- rsferrstr = "Can't create SFile, Internal error";
- }
-
- #else
- switch(errno) {
- case EINVAL:
- rsferrno = ESFNOTOPEN;
- rsferrstr = "Can't create SFile, Illegal filename";
- break;
- case EEXIST:
- rsferrno = ESFDUPFNAME;
- rsferrstr = "Can't create SFile, already exists";
- break;
- case EACCES:
- rsferrno = ESFNOTOPEN;
- rsferrstr = "Can't create SFile, permission denied";
- break;
- default:
- rsferrno = ESFNOTOPEN;
- rsferrstr = "Can't create SFile, Internal error";
- }
- #endif
- freesffile(i);
- return -1;
- }
- if(size < 0)
- f->sizerequested = freespace;
- else if(size >= freespace) {
- rsferrno = ESFNOSPACE;
- rsferrstr = "Not enough space on Disk to create sound file";
- #if defined _WIN32
- CloseHandle(f->fileno);
- DeleteFile(f->filename);
- #else
- fclose(f->fileno);
- remove(f->filename);
- #endif
-
- freesffile(i);
- return -1;
- } else
- f->sizerequested = (size/* + 1*/)/* &~1*/; /*RWD use size+1) to get 16bit pad for 24bit files */
- f->readonly = 0;
- f->header_set = 0;
- ///RWD.6.5.99 prepare peak storage: wave and binary envelope are OK
- if(props->type == wt_wave || props->type== wt_binenv){
- f->peaks = (CHPEAK *) calloc(props->chans, sizeof(CHPEAK));
- if(f->peaks==NULL){
- rsferrno = ESFNOMEM;
- rsferrstr = "No memory to create peak data storage";
- #if defined _WIN32
- CloseHandle(f->fileno);
- DeleteFile(f->filename);
- #else
- fclose(f->fileno);
- remove(f->filename);
- #endif
- freesffile(i);
- return -1;
- }
- }
- switch(f->filetype = gettypefromname98(f->filename)) {
- char *ext;
- /******* RWD.7.98 all we have to do to write a requested format is to fill in the data in f->fmtchunk
- ******* and get wrwavhdr() to read this in! *****/
- case riffwav:
- if(props->chformat >= MC_STD){
- f->filetype = wave_ex;
- props->format = WAVE_EX;
- rc = wrwavex(f, props);
- }
- else {
- props->chformat = STDWAVE;
- props->format = WAVE;
- rc = wrwavhdr98(f,props->chans,props->srate,stype);
- }
- break;
- //TODO: get the aiff extended formats sorted!
- case eaaiff:
- //for now, we have to IGNORE chformat requests
- props->chformat = STDWAVE;
- props->format = AIFF;
- //make sure AIFF format is legal!
- if(stype==SAMP_2432){
- stype = SAMP_2424;
- props->samptype = INT2424;
- }
- if(stype==SAMP_FLOAT){
- //we now require AIFC for float formats
- props->format = AIFC;
- f->filetype = aiffc;
- rc = wraifchdr(f,props->chans,props->srate,stype);
- }
- else
- rc = wraiffhdr98(f,props->chans,props->srate,stype);
- break;
- case aiffc:
- props->format = AIFC;
- //make sure AIFF format is legal!
- if(stype==SAMP_2432){
- stype = SAMP_2424;
- props->samptype = INT2424;
- }
- rc = wraifchdr(f,props->chans,props->srate,stype);
- break;
- case cdpfile:
- /* RWD MAR 2015 as above */
- if((ext = getenv("CDP_SOUND_EXT")) == NULL || strlen(ext) == 0) {
- ext = ext_default;
- }
- if(_stricmp(ext, "wav") == 0){
- if(props->chformat > MC_STD){
- f->filetype = wave_ex;
- props->format = WAVE_EX;
- rc = wrwavex(f, props);
- }
- else {
- props->chformat = STDWAVE;
- props->format = WAVE;
- rc = wrwavhdr98(f,props->chans,props->srate,stype);
- f->filetype = riffwav;
- }
- }
- else if(_stricmp(ext, "aif") == 0 || _stricmp(ext, "aiff") == 0){
- props->chformat = STDWAVE;
- props->format = AIFF;
- if(stype==SAMP_FLOAT){
- //we now require AIFC for float formats
- props->format = AIFC;
- f->filetype = aiffc;
- rc = wraifchdr(f,props->chans,props->srate,stype);
- }
- else {
- rc = wraiffhdr98(f,props->chans,props->srate,stype);
- f->filetype= eaaiff;
- }
- }
- //RWD.1.99 temporary
- else if(_stricmp(ext, "aic") == 0
- || _stricmp(ext, "afc") == 0
- || _stricmp(ext, "aifc") == 0){
- props->format = AIFC;
- f->filetype = aiffc;
- rc = wraifchdr(f,props->chans,props->srate,stype);
- }
- else {
- rsferrno = ESFBADPARAM;
- rsferrstr = "unknown sound file type - bad CDP_SOUND_EXT setting";
- //RWD.7.99
- #if defined _WIN32
- CloseHandle(f->fileno);
- DeleteFile(f->filename);
- #else
- fclose(f->fileno);
- remove(f->filename);
- #endif
- return -1;
- }
- break;
-
- default:
- rsferrno = ESFNOSTYPE;
- rsferrstr = "Internal error: can't find filetype";
- rc = 1;
- }
- if(rc) {
- //RWD.7.99
- #if defined _WIN32
- CloseHandle(f->fileno);
- DeleteFile(f->filename);
- #else
- fclose(f->fileno);
- remove(f->filename);
- #endif
- freesffile(i);
- return -1;
- }
- f->datachunksize = 0;
- f->infochanged = 0;
- f->todelete = 0;
- if(outsize != 0)
- *outsize = f->sizerequested;
- f->curpos = 0;
- if(props->type==wt_analysis){
- /*Write all pvoc properties*/
- if(addprop(f,"original sampsize",(char *)&(props->origsize), sizeof(/*long*/int))<0){
- rsferrstr = "Failure to write original sample size";
- return -1;
- }
- if(addprop(f,"original sample rate",(char *)&(props->origrate),sizeof(/*long*/int))<0){
- rsferrstr = "Failure to write original sample rate";
- }
- if(addprop(f,"arate",(char *)&(props->arate),sizeof(float)) < 0){
- rsferrstr = "Failure to write analysis sample rate";
- }
- if(addprop(f,"analwinlen",(char *)&(props->winlen),sizeof(int)) < 0){
- rsferrstr = "Failure to write analysis window length";
- }
- if(addprop(f,"decfactor",(char *)&(props->decfac),sizeof(int)) < 0){
- rsferrstr = "Failure to write decimation factor";
- }
- }
- return i+SFDBASE;
- }
- //RWD.1.99 new func to enable current sfile (e.g temporary) to be reopened for writing
- //return 1 for success, 0 for error
- //new channel/sample formats are accepted, but the cdp_create_mode cannot be changed, nor the file format
- //(without alot mre jiggery-pokery...)
- //BIG QUESTION: ALLOW THIS ONLY FOR TEMPORARY FILES?
- //note we do not call freesfile[] here, as the file is owned externally
- //current dependency: GRAINMILL
- //will need sndrecreat_formatted eventually, NB set buffer size for 24bit formats!
- int
- sfrecreat_formatted(int sfd, __int64 size, __int64 *outsize,int channels,
- int srate, int stype)
- {
- int rc;
- struct sf_file *f;
- char *ext_default = "wav";
- __int64 freespace;
- //might as well validate the params
- if(channels < 1 || srate <= 0)
- return 0;
- //ho hum, need stype as a typedef...
- // we're not interested in 8-bit stuff!
- if((stype >= SAMP_MASKED) || stype == SAMP_BYTE)
- return 0;
- if((f = findfile(sfd)) == 0)
- return 0;
- //RWD: this is OK, as it tells us we cannot CREATE more than one file of the same name, or one already opened
- if(f->refcnt > 1) {
- rsferrno = ESFNOTOPEN;
- rsferrstr = "Can't (re)create file more than once!";
- return 0;
- }
- if(f->readonly == 1)
- return 0;
- #if defined _WIN32
- if(w_ch_size(f->fileno, 0L) < 0) {
- #else
- if(ftruncate(fileno(f->fileno), 0) < 0) {
- #endif
- rsferrno = ESFWRERR;
- rsferrstr = "write error resetting file";
- return 0;
- }
- freespace = getdrivefreespace(f->filename) - LEAVESPACE;
- if(size < 0)
- f->sizerequested = freespace;
- else if((unsigned long)size >= freespace) {
- rsferrno = ESFNOSPACE;
- rsferrstr = "Not enough space on Disk to create sound file";
- return 0;
- } else
- f->sizerequested = /*size&~1*/ size; /*RWD Nov 2001: accept 24bit samples */
- f->readonly = 0;
- f->header_set = 0;
- //RWD.6.5.99 : accept PEAKS for now, but may need to forbid unless wave or binenv, as above
- if(f->peaks){
- free(f->peaks);
- f->peaks = (CHPEAK *) calloc(channels,sizeof(CHPEAK));
- if(f->peaks==NULL){
- rsferrno = ESFNOMEM;
- rsferrstr = "No memory for peak data";
- return 0;
- }
- }
- //we don't change f->min_header...
- switch(f->filetype) {
- char *ext;
- case riffwav:
- rc = wrwavhdr98(f,channels,srate,stype);
- break;
- case eaaiff:
- //make sure AIFF format is legal!
- if(stype==SAMP_2432){
- //reject here, as can't tell caller
- rsferrno = ESFBADPARAM;
- rsferrstr = "requested sample type illegal for AIFF files";
- return -1;
- }
- if(stype==SAMP_FLOAT){
- //we now require AIFC for float formats
- f->filetype = aiffc;
- rc = wraifchdr(f,channels,srate,stype);
- }
- else
- rc = wraiffhdr98(f,channels,srate,stype);
- break;
- case aiffc:
- //make sure AIFF format is legal!
- if(stype==SAMP_2432){
- //reject here, as can't tell caller
- rsferrno = ESFBADPARAM;
- rsferrstr = "requested sample type illegal for AIFF files";
- return -1;
- }
- rc = wraifchdr(f,channels,srate,stype);
- break;
- case cdpfile:
- /* RWD MAR 2015 as above */
- if((ext = getenv("CDP_SOUND_EXT")) == NULL || strlen(ext) == 0) {
- // rsferrno = ESFBADPARAM;
- // rsferrstr = "unknown sound file type - extension not set";
- // rc = 1;
- ext = ext_default;
- }
- if(_stricmp(ext, "wav") == 0){
- rc = wrwavhdr98(f,channels,srate,stype);
- f->filetype = riffwav;
- }
- else if(_stricmp(ext, "aif") == 0 || _stricmp(ext, "aiff") == 0){
- if(stype==SAMP_FLOAT){
- //we now require AIFC for float formats
- f->filetype = aiffc;
- rc = wraifchdr(f,channels,srate,stype);
- }
- else {
- rc = wraiffhdr98(f,channels,srate,stype);
- f->filetype= eaaiff;
- }
- }
- //RWD.1.99 temporary
- else if(_stricmp(ext, "aic") == 0
- || _stricmp(ext, "afc") == 0
- || _stricmp(ext, "aifc") == 0){
- f->filetype = aiffc;
- rc = wraifchdr(f,channels,srate,stype);
- }
- else {
- rsferrno = ESFBADPARAM;
- rsferrstr = "unknown sound file type - bad CDP_SOUND_EXT setting";
- rc = 1;
- }
- break;
- default:
- rsferrno = ESFNOSTYPE;
- rsferrstr = "Internal error: can't find filetype";
- rc = 1;
- }
- if(rc) {
- return 0;
- }
- f->datachunksize = 0;
- f->infochanged = 0;
- f->todelete = 0;
- if(outsize != 0)
- *outsize = f->sizerequested;
- f->curpos = 0;
- return 1;
- }
- //RWD OCT97
- int
- sfgetwordsize(int sfd)
- {
- struct sf_file *f;
- if((f = findfile(sfd)) == 0)
- return -1;
- return f->fmtchunkEx.Format.wBitsPerSample;
- }
- __int64 sfgetdatasize(int sfd)
- {
- struct sf_file *f;
- if((f = findfile(sfd)) == 0)
- return -1;
- return f->datachunksize;
- }
- #if defined _WIN32
- int sf_is_shortcut(int sfd,char *name)
- {
- struct sf_file *f;
- if((f = findfile(sfd)) == 0)
- return -1;
- if(f->is_shortcut){
- if(name != NULL)
- strcpy(name,f->filename);
- }
- return f->is_shortcut;
- }
- #endif
- /*RWD: nb cnt arg is seen as count of BYTES to fill (expecting cnt/sizeof(sample) words);
- f->curpos expected to contain bytes of SHORTS or FLOATS
- */
- int
- sfread(int sfd, char *buf, int cnt)
- {
- struct sf_file *f;
- short *sp;
- DWORD *dp;
- __int64 remain;
- int i;
- //int got = 0;
- if((f = findfile(sfd)) == 0)
- return -1;
- cnt = cnt & ~(SECSIZE-1);
- /*RWD OCT97: here, remain IS size-specific, so curpos must be, too*/
- if((remain = (int)(f->datachunksize - f->curpos)) < 0)
- remain = 0;
- if(cnt > remain)
- cnt = remain;
- if(cnt == 0)
- return 0;
- if(f->fmtchunkEx.Format.wBitsPerSample == 8)
- cnt /= 2; /*see below...*/
- if(doread(f, buf, cnt)) { /*bytes, bytecnt*/
- rsferrno = ESFRDERR;
- rsferrstr = "Read error";
- return -1;
- }
- switch(f->fmtchunkEx.Format.wBitsPerSample) {
- case 8:
- if(f->filetype == riffwav || f->filetype ==wave_ex) {
- for(i = cnt-1; i >= 0; i--)
- ((short *)buf)[i] = (buf[i]-128)<<8;
- } else if((f->filetype == eaaiff) || (f->filetype==aiffc)) { //RWD.1.99
- for(i = cnt-1; i >= 0; i--)
- ((short *)buf)[i] = ((signed char *)buf)[i];
- } else
- abort(); //RWD ouch!
- cnt *= 2; // restored from above
- break;
- case 16:
- if(REVDATAINFILE(f)) {
- sp = (short *)buf;
- for(i = cnt/sizeof(short); i > 0; i--) {
- *sp = REVWBYTES(*sp);
- sp++;
- }
- }
- break;
- case 32:
- if(REVDATAINFILE(f)) {
- dp = (DWORD *)buf;
- for(i = cnt/sizeof(DWORD); i > 0; i--) {
- *dp = REVDWBYTES(*dp);
- dp++;
- }
- }
- break;
- default:
- // abort(); // ouch again!
- //RW.6.99
- rsferrno = ESFBADPARAM;
- rsferrstr = "cannot read unsupported sample type";
- return -1;
- }
- f->curpos += cnt; //assumes pos in SHORTS or FLOATS buffer
- return cnt;
- }
- //RWD: the original func - no support for new formats, but must eliminate abort() call!
- /* RWD 2007 NB : these funcs all return -1 for error, so are forced to handle only signed longs */
- /* therefore: NOT ready for 4GB files ! */
- int
- sfwrite(int sfd, char *outbuf, int cnt)
- {
- struct sf_file *f;
- int i;
- __int64 remain;
- short *ssp, *sdp;
- DWORD *dsp, *ddp;
- char *buf = outbuf;
- if((f = findfile(sfd)) == 0)
- return -1;
- if(f->readonly) {
- rsferrno = ESFREADONLY;
- rsferrstr = "Can't write to read only file";
- return -1;
- }
- if(f->fmtchunkEx.Format.wBitsPerSample == 8) {
- rsferrno = ESFREADONLY;
- rsferrstr = "Can't write to 8bits/sample files";
- return -1;
- }
- cnt = cnt & ~(SECSIZE-1);
- if(f->sizerequested >= 0) { /* creating file - explicit size */
- if((remain = f->sizerequested - f->curpos) < 0)
- remain = 0;
- if(cnt > (int) remain)
- cnt = (int) remain;
- } else if(f->sizerequested == ES_EXIST) { /* existing file - can't change size */
- if((remain = f->datachunksize - f->curpos) < 0)
- remain = 0;
- if(cnt > (int) remain)
- cnt = (int) remain;
- }
- if(cnt == 0)
- return 0;
- if(REVDATAINFILE(f)) {
- if((buf = (char *) malloc(cnt)) == 0) {
- rsferrno = ESFWRERR;
- rsferrstr = "Write error: can't allocate byte swap buffer";
- return -1;
- }
- switch(f->fmtchunkEx.Format.wBitsPerSample) {
- case 16:
- ssp = (short *)outbuf;
- sdp = (short *)buf;
- for(i = cnt/sizeof(short); i > 0; i--) {
- *sdp = REVWBYTES(*ssp);
- ssp++;
- sdp++;
- }
- break;
- case 32:
- dsp = (DWORD *)outbuf;
- ddp = (DWORD *)buf;
- for(i = cnt/sizeof(DWORD); i > 0; i--) {
- *ddp = REVDWBYTES(*dsp);
- dsp++;
- ddp++;
- }
- break;
- default:
- #ifdef NOTDEF
- abort();
- #endif
- rsferrno = ESFBADPARAM;
- rsferrstr = "cannot write unsupported sample format";
- return -1;
- }
- }
- /* else creating file - max size */
- if(dowrite(f, buf, cnt)) {
- rsferrno = ESFWRERR;
- rsferrstr = "Write error";
- if(buf != outbuf)
- free(buf);
- return -1;
- }
- f->curpos += cnt;
- if(f->curpos > f->datachunksize) {
- f->datachunksize = f->curpos;
- f->infochanged = 1;
- }
- if(buf != outbuf)
- free(buf);
- return cnt;
- }
- /* RWD: OBSOLETE - NOT IN USE NOW! */
- int
- sfseek(int sfd, int dist, int whence)
- {
- struct sf_file *f;
- unsigned int newpos = 0u;
- unsigned int size;
- fpos_t bytepos;
- if((f = findfile(sfd)) == 0)
- return -1;
- /*RWD 2007 added casts to silence compiler! */
- size = (unsigned int) sfsize(sfd); /* NB Can't fail! */ //RWD OCT97: NB: assumes file of SHORTS or FLOATS
- switch(whence) {
- case 0:
- newpos = dist;
- break;
- case 1:
- newpos = f->curpos + dist;
- break;
- case 2:
- newpos = size + dist;
- break;
- default:
- rsferrno = ESFBADPARAM;
- rsferrstr = "illegal whence value in sfseek";
- break;
- }
- /* RWD MAR 2015 just to eliminate compiler warning */
- //if(newpos < 0)
- // newpos = 0;
- if(newpos > size)
- newpos = size;
- newpos &= ~(SECSIZE-1);
- f->curpos = newpos; //still size-specific here...
- //RWD OCT97 must seek correctly in 8bit files
- if(f->fmtchunkEx.Format.wBitsPerSample==8)
- newpos /= 2;
- #if defined _WIN32
- newpos += f->datachunkoffset;
- if(SetFilePointer(f->fileno, newpos,NULL, FILE_BEGIN) != newpos) {
- #else
- POS64(bytepos) = newpos + POS64(f->datachunkoffset);
- if(fsetpos(f->fileno, &bytepos) ) {
- #endif
- rsferrno = ESFRDERR; //RWD CDP97
- rsferrstr = "Seek error";
- return -1;
- }
- return f->curpos;
- }
- static char * REV3BYTES(char *samp_24){
- //trick here: just exchange the outer bytes!
- char temp = samp_24[0];
- *samp_24 = samp_24[2];
- samp_24[2] = temp;
- return samp_24;
- }
- /* special buffered sf_routines for new sample sizes */
- int
- sfread_buffered(int sfd, char *buf, int lcnt)
- {
- struct sf_file *f;
- short *sp;
- DWORD *dp;
- #ifdef FILE64_WIN
- __int64 remain,i;
- __int64 cnt = lcnt; /*RWD 2007: lcnt used some places below */
- long containersize;
- #else
- __int64 remain;
- __int64 cnt = lcnt;
- int i,containersize;
- #endif
- //int got = 0;
- if((f = findfile(sfd)) == 0)
- return -1;
- //RWD OCT97: here, remain IS size-specific, so curpos must be, too
- if((remain = (__int64) (f->datachunksize - f->curpos)) < 0)
- remain = 0;
- #ifdef FILE64_WIN
- if((__int64) cnt > remain)
- cnt = (unsigned int) remain;
- #else
- if(cnt > remain)
- cnt = remain;
- #endif
- if(cnt == 0)
- return 0;
- if(f->fmtchunkEx.Format.wBitsPerSample == 8)
- cnt /= 2; //see below...
- if(doread(f, buf, (int) cnt)) { //bytes, bytecnt
- rsferrno = ESFRDERR;
- rsferrstr = "Read error";
- return -1;
- }
- containersize = 8 * (f->fmtchunkEx.Format.nBlockAlign / f->fmtchunkEx.Format.nChannels);
- switch(containersize) {
- case 8:
- if(f->filetype == riffwav || f->filetype ==wave_ex) {
- for(i = cnt-1; i >= 0; i--)
- ((short *)buf)[i] = (buf[i]-128)<<8;
- } else if((f->filetype == eaaiff) || (f->filetype==aiffc)) { //RWD.1.99
- for(i = cnt-1; i >= 0; i--)
- ((short *)buf)[i] = ((signed char *)buf)[i];
- } else
- abort(); //RWD ouch!
- cnt *= 2; // restored from above
- break;
- case 16:
- if(REVDATAINFILE(f)) {
- sp = (short *)buf;
- for(i = cnt/sizeof(short); i > 0; i--) {
- *sp = REVWBYTES(*sp);
- sp++;
- }
- }
- break;
- case(24):
- if(REVDATAINFILE(f)) {
- char *p_byte = buf;
- for(i = cnt/3; i > 0; i--) {
- p_byte = REV3BYTES(p_byte);
- p_byte += 3;
- }
- }
- break;
- case 32:
- if(REVDATAINFILE(f)) {
- dp = (DWORD *)buf;
- for(i = cnt/sizeof(DWORD); i > 0; i--) {
- *dp = REVDWBYTES(*dp);
- dp++;
- }
- }
- break;
- default:
- #ifdef NOTDEF
- abort(); // ouch again!
- #endif
- rsferrno = ESFBADPARAM;
- rsferrstr = "unsupported sample format";
- return -1;
- }
- f->curpos += (DWORD) cnt; //assumes pos in SHORTS or FLOATS buffer
- return (int) cnt;
- }
- //RWD.7.99 TODO: use blockalign to decide what size word to write
- int
- sfwrite_buffered(int sfd, char *outbuf, int lcnt)
- {
- struct sf_file *f;
- __int64 remain;
- __int64 cnt = lcnt;
- short *ssp, *sdp;
- DWORD *dsp, *ddp;
- char *buf = outbuf;
- int containersize;
- if((f = findfile(sfd)) == 0)
- return -1;
- if(f->readonly) {
- rsferrno = ESFREADONLY;
- rsferrstr = "Can't write to read only file";
- return -1;
- }
- if(f->fmtchunkEx.Format.wBitsPerSample == 8) {
- rsferrno = ESFREADONLY;
- rsferrstr = "Can't write to 8bits/sample files";
- return -1;
- }
- //cnt = cnt & ~(SECSIZE-1);
- if(f->sizerequested >= 0) { /* creating file - explicit size */
- if((remain = f->sizerequested - f->curpos) < 0)
- remain = 0;
- if(cnt > remain)
- cnt = remain;
- } else if(f->sizerequested == ES_EXIST) { /* existing file - can't change size */
- if((remain = f->datachunksize - f->curpos) < 0)
- remain = 0;
- if(cnt > remain)
- cnt = remain;
- }
- if(cnt == 0)
- return 0;
- containersize = 8 * (f->fmtchunkEx.Format.nBlockAlign / f->fmtchunkEx.Format.nChannels);
- if(REVDATAINFILE(f)) {
- int i; /* RWD Feb 2010: should be OK as signed; too risky unsigned in a loop! */
- if((buf = (char *) malloc((size_t) cnt)) == 0) { /*RWD 2007 */
- rsferrno = ESFWRERR;
- rsferrstr = "Write error: can't allocate byte swap buffer";
- return -1;
- }
- switch(containersize) {
- char *p_byte;
- char *p_buf;
- case 16:
- ssp = (short *)outbuf;
- sdp = (short *)buf;
- for(i = cnt/sizeof(short); i > 0; i--) {
- *sdp = REVWBYTES(*ssp);
- ssp++;
- sdp++;
- }
- break;
- case 32:
- dsp = (DWORD *)outbuf;
- ddp = (DWORD *)buf;
- for(i = cnt/sizeof(DWORD); i > 0; i--) {
- *ddp = REVDWBYTES(*dsp);
- dsp++;
- ddp++;
- }
- break;
- //case 20:
- case 24:
- p_byte = outbuf;
- p_buf = buf;
- for(i= cnt/3; i > 0; i--){
- p_buf[0] = p_byte[2];
- p_buf[1] = p_byte[1];
- p_buf[2] = p_byte[0];
- p_byte += 3;
- p_buf += 3;
- }
- break;
- default:
- //abort();
- rsferrno = ESFBADPARAM;
- rsferrstr = "unsupported sample format";
- if(buf != outbuf)
- free(buf);
- return -1;
- break;
- }
- }
- /* else creating file - max size */
- if(dowrite(f, buf, (int) cnt)) {
- rsferrno = ESFWRERR;
- rsferrstr = "Write error";
- if(buf != outbuf)
- free(buf);
- return -1;
- }
- f->curpos += (DWORD) cnt;
- if(f->curpos > (DWORD) f->datachunksize) {
- f->datachunksize = f->curpos;
- f->infochanged = 1;
- }
- if(buf != outbuf)
- free(buf);
- return (int) cnt;
- }
- /* RWD PVX... maybe still need FILE64_WIN? */
- //#ifdef FILE64_WIN
- #ifdef _WIN32
- /* RWD 2007 remember dist can be negative... */
- __int64
- sfseek_buffered(int sfd, __int64 dist, int whence)
- {
- struct sf_file *f;
- __int64 newpos = 0;
- __int64 i64size;
- LARGE_INTEGER pos64;
- if((f = findfile(sfd)) == 0)
- return -1;
- i64size = sfsize(sfd); /* NB Can't fail! */ //RWD OCT97: NB: assumes file of SHORTS or FLOATS
- switch(whence) {
- case 0:
- newpos = dist;
- break;
- case 1:
- newpos = (__int64) f->curpos + dist;
- break;
- case 2:
- newpos = i64size + dist;
- break;
- default:
- rsferrno = ESFBADPARAM;
- rsferrstr = "illegal whence value in sfseek";
- break;
- }
- if(newpos < 0)
- newpos = 0;
- if(newpos > i64size)
- newpos = i64size;
- f->curpos = (unsigned int) newpos; //still size-specific here...
- //RWD OCT97 must seek correctly in 8bit files
- if(f->fmtchunkEx.Format.wBitsPerSample==8)
- newpos /= 2;
- newpos += f->datachunkoffset;
- //#endif
- #if defined _WIN32
- pos64.QuadPart = newpos;
- pos64.LowPart = SetFilePointer(f->fileno, pos64.LowPart,&pos64.HighPart, FILE_BEGIN);
- if(pos64.LowPart==0xFFFFFFFF && GetLastError() != NO_ERROR){
- /* != newpos) { */
- rsferrno = ESFRDERR; //RWD CDP97
- rsferrstr = "Seek error";
- return -1;
- }
- if(pos64.QuadPart != newpos){
- rsferrno = ESFRDERR;
- rsferrstr = "Seek error";
- return -1;
- }
- #else
- if(lseek(f->fileno, newpos, SEEK_SET) != newpos) {
- rsferrno = ESFRDERR; //RWD CDP97
- rsferrstr = "Seek error";
- return -1;
- }
- #endif
- return f->curpos;
- }
- #else
- __int64
- sfseek_buffered(int sfd, __int64 dist, int whence)
- {
- struct sf_file *f;
- __int64 newpos = 0; // allow max seek distance 2GB
- __int64 size;
- fpos_t bytepos;
- if((f = findfile(sfd)) == 0)
- //return -1;
- return 0xFFFFFFFF;
- size = sfsize(sfd); /* NB Can't fail! */ //RWD OCT97: NB: assumes file of SHORTS or FLOATS
- switch(whence) {
- case 0:
- newpos = dist;
- break;
- case 1:
- newpos = f->curpos + dist;
- break;
- case 2:
- newpos = size + dist;
- break;
- default:
- rsferrno = ESFBADPARAM;
- rsferrstr = "illegal whence value in sfseek";
- break;
- }
- if(newpos < 0)
- newpos = 0;
- if(newpos > size)
- newpos = size;
- f->curpos = (DWORD) newpos; //still size-specific here...
- //RWD OCT97 must seek correctly in 8bit files
- if(f->fmtchunkEx.Format.wBitsPerSample==8)
- newpos /= 2;
- //
- //#endif
- #if defined _WIN32
- newpos += f->datachunkoffset;
- if(SetFilePointer(f->fileno, newpos,NULL, FILE_BEGIN) != newpos) {
- #else
- POS64(bytepos) = (DWORD) newpos + POS64(f->datachunkoffset);
- if(fsetpos(f->fileno, &bytepos)) {
- #endif
- rsferrno = ESFRDERR; //RWD CDP97
- rsferrstr = "Seek error";
- return -1;
- }
- return (__int64) f->curpos;
- }
- #endif
- //RWD: this may not be sufficient: we may want to distinguish betweeen
- // float sfiles and analfiles....
- static int
- wavupdate(struct sf_file *f)
- {
- unsigned long seekdist;
- fpos_t bytepos;
- switch(f->fmtchunkEx.Format.wBitsPerSample) {
- case 8:
- f->fmtchunkEx.Format.nAvgBytesPerSec = f->fmtchunkEx.Format.nBlockAlign = f->fmtchunkEx.Format.nChannels;
- f->datachunksize /= 2;
- break;
- case 16:
- f->fmtchunkEx.Format.nAvgBytesPerSec = f->fmtchunkEx.Format.nBlockAlign = f->fmtchunkEx.Format.nChannels * 2;
- break;
- case 32:
- f->fmtchunkEx.Format.nAvgBytesPerSec = f->fmtchunkEx.Format.nBlockAlign = f->fmtchunkEx.Format.nChannels * 4;
- f->fmtchunkEx.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; //RWD 07:97
- //RWD TODO: update 'fact' chunk with num-samples
- break;
- default:
- abort();
- }
- f->fmtchunkEx.Format.nAvgBytesPerSec *= f->fmtchunkEx.Format.nSamplesPerSec;
- //add space for fact chunk ?
- //WARNING: THIS HAS NOT BEEN FULLY TESTED!
- // maxsamp needed this...writes directly to existing header on disk
- //f->extrachunksizes = 3*sizeof(DWORD);
- f->mainchunksize = POS64(f->datachunkoffset) + (DWORD) f->datachunksize - 2*sizeof(DWORD) + f->extrachunksizes;
- #if defined _WIN32
- if(SetFilePointer(f->fileno, 4L,NULL, FILE_BEGIN)== 0xFFFFFFFF
- #else
- if(fseek(f->fileno, 4L, SEEK_SET) < 0
- #endif
- || write_dw_lsf(f->mainchunksize, f)
- #if defined _WIN32
- || SetFilePointer(f->fileno, f->fmtchunkoffset,NULL, FILE_BEGIN)== 0xFFFFFFFF
- || write_w_lsf(f->fmtchunkEx.Format.wFormatTag, f)
- || write_w_lsf(f->fmtchunkEx.Format.nChannels, f)
- || write_dw_lsf(f->fmtchunkEx.Format.nSamplesPerSec, f)
- || write_dw_lsf(f->fmtchunkEx.Format.nAvgBytesPerSec, f)
- || write_w_lsf(f->fmtchunkEx.Format.nBlockAlign, f)
- || write_w_lsf(f->fmtchunkEx.Format.wBitsPerSample, f)){
- rsferrno = ESFWRERR;
- rsferrstr = "Write error: Can't update format data";
- return -1;
- }
- #else
- || fsetpos(f->fileno, &f->fmtchunkoffset)
- || write_w_lsf(f->fmtchunkEx.Format.wFormatTag, f)
- || write_w_lsf(f->fmtchunkEx.Format.nChannels, f)
- || write_dw_lsf(f->fmtchunkEx.Format.nSamplesPerSec, f)
- || write_dw_lsf(f->fmtchunkEx.Format.nAvgBytesPerSec, f)
- || write_w_lsf(f->fmtchunkEx.Format.nBlockAlign, f)
- || write_w_lsf(f->fmtchunkEx.Format.wBitsPerSample, f)){
- rsferrno = ESFWRERR;
- rsferrstr = "Write error: Can't update format data";
- return -1;
- }
- #endif
- //RWD OCT97: the extra cbSize field SHOULD be there, = 0
- //fact chunk contains size in samples
- if(f->fmtchunkEx.Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT){
- if(POS64(f->factchunkoffset) > 0){ /*RWD 01:2004 */
- #if defined _WIN32
- if(SetFilePointer(f->fileno,f->factchunkoffset,NULL,FILE_BEGIN)== 0xFFFFFFFF
- #else
- if(fsetpos(f->fileno,&f->factchunkoffset)
- #endif
- ||write_dw_lsf((DWORD)(f->datachunksize / (f->fmtchunkEx.Format.wBitsPerSample / sizeof(char))),f)){ /*RWD 2007 */
- rsferrno = ESFWRERR;
- rsferrstr = "Write error: Can't update fact chunk for floatsam data";
- return -1;
- }
- }
- }
- #if defined _WIN32
- if(SetFilePointer(f->fileno, f->datachunkoffset - sizeof(DWORD),NULL, FILE_BEGIN)== 0xFFFFFFFF
- #else
- seekdist = POS64(f->datachunkoffset) - sizeof(DWORD);
- POS64(bytepos) = seekdist;
- if(fsetpos(f->fileno, &bytepos)
- #endif
- ||write_dw_lsf((DWORD) f->datachunksize, f) ) { /*RWD 2007 */
- rsferrno = ESFWRERR;
- rsferrstr = "Write error: Can't update data size";
- return -1;
- }
- return 0;
- }
- /******* SFSY98 VERSION*******
- ******* main format data already there - just update durations
- */
- //RWD.5.99 TODO: need to be more clever with extended formats:
- //must distinguish 32bit int and float
- //this is used when header has already been set
- static int
- wavupdate98(time_t thistime, struct sf_file *f)
- {
- fpos_t bytepos;
- if(! f->header_set)
- return -1;
- if(f->fmtchunkEx.Format.wBitsPerSample == 8)
- f->datachunksize /= 2;
- f->mainchunksize = POS64(f->datachunkoffset) + (DWORD) f->datachunksize - 2*sizeof(DWORD) + f->extrachunksizes;
- #if defined _WIN32
- if(SetFilePointer(f->fileno, 4L,NULL, FILE_BEGIN)== 0xFFFFFFFF
- #else
- if(fseek(f->fileno, 4L, SEEK_SET) < 0
- #endif
- ||write_dw_lsf(f->mainchunksize, f)){
- rsferrno = ESFWRERR;
- rsferrstr = "SFSY98: Write error: Can't update datachunk size";
- return -1;
- }
- #ifdef NOTDEF
- if(f->infochanged){
- #ifdef _WIN32
- if(SetFilePointer(f->fileno, f->fmtchunkoffset,NULL, FILE_BEGIN)== 0xFFFFFFFF
- #else
- if(fsetpos(f->fileno, &f->fmtchunkoffset)
- #endif
- ||write_w_lsf(f->fmtchunkEx.Format.wFormatTag, f)
- ||write_w_lsf(f->fmtchunkEx.Format.nChannels, f)
- ||write_dw_lsf(f->fmtchunkEx.Format.nSamplesPerSec, f)
- ||write_dw_lsf(f->fmtchunkEx.Format.nAvgBytesPerSec, f)
- ||write_w_lsf(f->fmtchunkEx.Format.nBlockAlign, f)
- ||write_w_lsf(f->fmtchunkEx.Format.wBitsPerSample, f)){
- rsferrno = ESFWRERR;
- rsferrstr = "SFSYS98: Write error: Can't update chunk sizes or info chunk";
- return -1;
- }
- }
- #endif
- if(f->fmtchunkEx.Format.wFormatTag == WAVE_FORMAT_IEEE_FLOAT){
- //fact chunk contains size in samples
- //RWD.5.99 may not be using it...
- if(POS64(f->factchunkoffset) > 0){
- #if defined _WIN32
- if(SetFilePointer(f->fileno,f->factchunkoffset,NULL,FILE_BEGIN)== 0xFFFFFFFF
- #else
- if(fsetpos(f->fileno,&f->factchunkoffset)
- #endif
- || write_dw_lsf((DWORD)(f->datachunksize / (f->fmtchunkEx.Format.wBitsPerSample / sizeof(char))),f)) {
- rsferrno = ESFWRERR;
- rsferrstr = "SFSYS98: Write error: Can't update fact chunk for floatsam file";
- return -1;
- }
- }
- }
- //RWD.6.5.99 update peak chunk
- if((f->min_header >= SFILE_PEAKONLY) && f->peaks){
- #if defined _WIN32
- if(SetFilePointer(f->fileno,f->peakchunkoffset + sizeof(DWORD),NULL,FILE_BEGIN)== 0xFFFFFFFF
- #else
- fpos_t target = f->peakchunkoffset;
- POS64(target) += sizeof(DWORD);
- //if(lseek(f->fileno,f->peakchunkoffset + sizeof(DWORD),SEEK_SET) < 0
- if(fsetpos(f->fileno,&target)
- #endif
- || write_dw_lsf((DWORD) thistime,f)
- || write_peak_lsf(f->fmtchunkEx.Format.nChannels,f)) {
- rsferrno = ESFWRERR;
- rsferrstr = "SFSYS98: Write error: Can't update peak chunk";
- return -1;
- }
- }
- #if defined _WIN32
- if(SetFilePointer(f->fileno, f->datachunkoffset - sizeof(DWORD),NULL, FILE_BEGIN)== 0xFFFFFFFF
- ||write_dw_lsf((DWORD) f->datachunksize, f) ) {
- #else
- bytepos = f->datachunkoffset;
- POS64(bytepos) -= sizeof(DWORD);
- //if(lseek(f->fileno, f->datachunkoffset - sizeof(DWORD), SEEK_SET) < 0
- // ||write_dw_lsf((DWORD) f->datachunksize, f) ) {
- if(fsetpos(f->fileno, &bytepos)
- ||write_dw_lsf((DWORD) f->datachunksize, f) ) {
- #endif
- rsferrno = ESFWRERR;
- rsferrstr = "SFSYS98: Write error: Can't update chunk sizes or info chunk";
- return -1;
- }
- return 0;
- }
- static int
- aiffupdate(time_t thistime,struct sf_file *f)
- {
- DWORD numsampleframes;
- fpos_t bytepos;
- struct aiffchunk *ap = f->aiffchunks;
- int commafterdata = 0;
- switch(f->fmtchunkEx.Format.wBitsPerSample) {
- case 8:
- f->datachunksize /= 2;
- numsampleframes = (DWORD) f->datachunksize; /* RWD 2007 added DWORD casts */
- break;
- case 16:
- numsampleframes = (DWORD) f->datachunksize / 2;
- break;
- case 32:
- numsampleframes = (DWORD) f->datachunksize / 4;
- break;
- default:
- abort();
- }
- numsampleframes /= f->fmtchunkEx.Format.nChannels;
- f->mainchunksize = sizeof(DWORD) + 2*sizeof(DWORD) + 26 + 2*sizeof(DWORD) + (DWORD)(f->datachunksize + f->extrachunksizes);
- #if defined _WIN32
- if(SetFilePointer(f->fileno,4L,NULL,FILE_BEGIN) == 0xFFFFFFFF
- ||write_dw_msf((DWORD) POS64(f->mainchunksize), f)
- ||SetFilePointer(f->fileno,(long)(POS64(f->datachunkoffset) - 3*sizeof(DWORD)),NULL,FILE_BEGIN) == 0xFFFFFFFF
- ||write_dw_msf((DWORD)(f->datachunksize + 2*sizeof(DWORD)), f) ) {
- rsferrno = ESFWRERR;
- rsferrstr = "Write error: Can't update main or data chunk size";
- return -1;
- }
- #else
- bytepos = f->datachunkoffset;
- POS64(bytepos) -= 3 * sizeof(DWORD);
- if(fseek(f->fileno, 4L, SEEK_SET)
- ||write_dw_msf((DWORD) f->mainchunksize, f)
- ||fsetpos(f->fileno, &bytepos)
- ||write_dw_msf((DWORD)(f->datachunksize + 2*sizeof(DWORD)), f) ) {
- rsferrno = ESFWRERR;
- rsferrstr = "Write error: Can't update main or data chunk size";
- return -1;
- }
- #endif
- if(POS64(f->fmtchunkoffset) > POS64(f->datachunkoffset)) {
- commafterdata++;
- POS64(f->fmtchunkoffset) = POS64(f->datachunkoffset) + (DWORD)( (f->datachunksize+1)&~1);
- }
- //RWD NB no support for AIFC here...
- #ifdef NOTDEF
- else
- f->fmtchunkoffset -= 2*sizeof(DWORD);
- #endif
- #if defined _WIN32
- if(SetFilePointer(f->fileno,f->fmtchunkoffset,NULL,FILE_BEGIN) == 0xFFFFFFFF){
- #else
- if(fsetpos(f->fileno, &f->fmtchunkoffset) ) {
- #endif
- rsferrno = ESFWRERR;
- rsferrstr = "Write error: Can't seek to COMM chunk";
- return -1;
- }
- if(
- #ifdef NOTDEF
- write_dw_msf(TAG('C','O','M','M'), f)
- ||write_dw_msf(18, f)
- ||
- #endif
- write_w_msf(f->fmtchunkEx.Format.nChannels, f)
- ||write_dw_msf(numsampleframes, f)
- ||write_w_msf(f->fmtchunkEx.Format.wBitsPerSample, f)
- ||write_dw_toex(f->fmtchunkEx.Format.nSamplesPerSec, f) ) {
- rsferrno = ESFWRERR;
- rsferrstr = "Write error: Can't update COMM chunk";
- return -1;
- }
- //RWD.6.5.99 update peak chunk
- if((f->min_header >= SFILE_PEAKONLY) && f->peaks){
- #if defined _WIN32
- if(SetFilePointer(f->fileno,f->peakchunkoffset + sizeof(DWORD),NULL,FILE_BEGIN)== 0xFFFFFFFF
- #else
- bytepos = f->peakchunkoffset;
- POS64(bytepos) += sizeof(DWORD);
- if(fsetpos(f->fileno,&bytepos)
- #endif
- || write_dw_msf((DWORD) thistime,f)
- || write_peak_msf(f->fmtchunkEx.Format.nChannels,f)) {
- rsferrno = ESFWRERR;
- rsferrstr = "SFSYS98: Write error: Can't update peak chunk";
- return -1;
- }
- }
- if(!commafterdata) {
- #if defined _WIN32
- if(SetFilePointer(f->fileno,(long)(f->datachunkoffset + (f->datachunksize+1)&~1),NULL,FILE_BEGIN)==0xFFFFFFFF) {
- #else
- bytepos = f->datachunkoffset;
- POS64(bytepos) += (f->datachunksize+1)&~1;
- if(fsetpos(f->fileno, &bytepos) ) {
- #endif
- rsferrno = ESFWRERR;
- rsferrstr = "Can't seek to end, to update extra chunks";
- return -1;
- }
- }
- for(; ap != 0; ap = ap->next) {
- if(POS64(ap->offset) < POS64(f->datachunkoffset))
- continue;
- if(write_dw_msf(ap->tag, f)
- ||write_dw_msf(ap->size, f)
- ||dowrite(f, ap->buf, (ap->size+1)&~1) ) {
- rsferrno = ESFWRERR;
- rsferrstr = "Can't update extra chunk";
- return -1;
- }
- }
- return 0;
- }
- static int
- aiffupdate98(time_t thistime,struct sf_file *f)
- {
- DWORD numsampleframes = 0;
- #ifdef linux
- fpos_t bytepos = {0};
- #else
- fpos_t bytepos = 0;
- #endif
- struct aiffchunk *ap = f->aiffchunks;
- int commafterdata = 0;
- if(! f->header_set)
- return -1;
- if(f->infochanged){
- switch(f->fmtchunkEx.Format.wBitsPerSample) {
- case 8:
- f->datachunksize /= 2;
- numsampleframes = (DWORD) f->datachunksize;
- break;
- case 16:
- numsampleframes = (DWORD) f->datachunksize/2;
- break;
- case 20: //NB not allowed by AIFF - no header field for masked sizes
- case 24:
- numsampleframes = (DWORD) f->datachunksize / 3;
- break;
- case 32:
- numsampleframes = (DWORD) f->datachunksize/4;
- break;
- default:
- rsferrno = ESFBADPARAM;
- rsferrstr = "cannot update with unknown sample format";
- return -1;
- break;
- }
- }
- // else if bitspersample== 8.... ?
- numsampleframes /= f->fmtchunkEx.Format.nChannels;
- /* RWD 8.99 this may be wrong...*/
- /*f->mainchunksize = sizeof(DWORD) + 2*sizeof(DWORD) + 26 + 2*sizeof(DWORD) + f->datachunksize + f->extrachunksizes;
- */
- f->mainchunksize = POS64(f->datachunkoffset) + (DWORD) f->datachunksize - 2 * sizeof(DWORD);
- #if defined _WIN32
- if(SetFilePointer(f->fileno,4L,NULL,FILE_BEGIN) == 0xFFFFFFFF
- #else
- bytepos = f->datachunkoffset;
- POS64(bytepos) -= 3*sizeof(DWORD);
- if(fseek(f->fileno, 4L, SEEK_SET) < 0
- #endif
- ||write_dw_msf(f->mainchunksize, f)
- #if defined _WIN32
- ||SetFilePointer(f->fileno,(long)(f->datachunkoffset - 3*sizeof(DWORD)),NULL,FILE_BEGIN) == 0xFFFFFFFF
- #else
- // ||lseek(f->fileno, f->datachunkoffset - 3*sizeof(DWORD), SEEK_SET) < 0
- ||fsetpos(f->fileno, &bytepos)
- #endif
- ||write_dw_msf((DWORD) f->datachunksize + 2*sizeof(DWORD), f) ) {
- rsferrno = ESFWRERR;
- rsferrstr = "Write error: Can't update main or data chunk size";
- return -1;
- }
- if(POS64(f->fmtchunkoffset) > POS64(f->datachunkoffset)) {
- commafterdata++;
- POS64(f->fmtchunkoffset) = POS64(f->datachunkoffset) + (DWORD)((f->datachunksize+1)&~1); /*RWD 2007 */
- }
- //RWD don't want to do this - might be AIFC - don't need to anyway!
- #ifdef NOTDEF
- else
- f->fmtchunkoffset -= 2*sizeof(DWORD);
- #endif
- #if defined _WIN32
- if(SetFilePointer(f->fileno,f->fmtchunkoffset,NULL,FILE_BEGIN) == 0xFFFFFFFF){
- #else
- if(fsetpos(f->fileno, &f->fmtchunkoffset) ) {
- #endif
- rsferrno = ESFWRERR;
- rsferrstr = "Write error: Can't seek to COMM chunk";
- return -1;
- }
- //strictly, we should check the new format and redo the AIFC stuff,
- //OR reject if infochanged
- //at least, disallow format conversion in AIFC!
- if(
- #ifdef NOTDEF
- write_dw_msf(TAG('C','O','M','M'), f)
- ||write_dw_msf(18, f)
- ||
- #endif
- write_w_msf(f->fmtchunkEx.Format.nChannels, f)
- ||write_dw_msf(numsampleframes, f)
- ||write_w_msf(f->fmtchunkEx.Format.wBitsPerSample, f)
- ||write_dw_toex(f->fmtchunkEx.Format.nSamplesPerSec, f) ) {
- rsferrno = ESFWRERR;
- rsferrstr = "Write error: Can't update COMM chunk";
- return -1;
- }
- // update peak chunk
- if((f->min_header >= SFILE_PEAKONLY) && f->peaks){
- #if defined _WIN32
- if(SetFilePointer(f->fileno,f->peakchunkoffset + sizeof(DWORD),NULL,FILE_BEGIN)== 0xFFFFFFFF
- #else
- bytepos = f->peakchunkoffset;
- POS64(bytepos) += sizeof(DWORD);
- if(fsetpos(f->fileno,&bytepos)
- #endif
- || write_dw_msf((DWORD) thistime,f)
- || write_peak_msf(f->fmtchunkEx.Format.nChannels,f)) {
- rsferrno = ESFWRERR;
- rsferrstr = "SFSYS98: Write error: Can't update peak chunk";
- return -1;
- }
- }
- if(!commafterdata) {
- #if defined _WIN32
- if(SetFilePointer(f->fileno,(long)(f->datachunkoffset + (f->datachunksize+1)&~1),NULL,FILE_BEGIN)==0xFFFFFFFF) {
- #else
- bytepos = f->datachunkoffset;
- POS64(bytepos) += (f->datachunksize+1)&~1;
- // if(lseek(f->fileno, f->datachunkoffset + (f->datachunksize+1)&~1, SEEK_SET) < 0) {
- if(fsetpos(f->fileno, &bytepos) ) {
- #endif
- rsferrno = ESFWRERR;
- rsferrstr = "Can't seek to end, to update extra chunks";
- return -1;
- }
- }
- /* RWD: NB if we have these, they will start correctly after a pad byte,
- * and we will just trust that these chunks are kosher!*/
- if(ap){
- for(; ap != 0; ap = ap->next) {
- if(POS64(ap->offset) < POS64(f->datachunkoffset))
- continue;
- if(write_dw_msf(ap->tag, f)
- ||write_dw_msf(ap->size, f)
- ||dowrite(f, ap->buf, (ap->size+1)&~1) ) {
- rsferrno = ESFWRERR;
- rsferrstr = "Can't update extra chunk";
- return -1;
- }
- }
- }
- /*RWD AIFF requires pad byte at end, for 8bit and 24bit sample types*/
- else {
- #ifdef FILE64_WIN
- __int64 size = f->datachunkoffset + (f->datachunksize+1)&~1;
- #else
- DWORD size = POS64(f->datachunkoffset) + ((f->datachunksize+1)&~1);
- #endif
- #if defined _WIN32
- if(w_ch_size(f->fileno, size) < 0) {
- #else
- if(ftruncate(fileno(f->fileno), (off_t) size) < 0) {
- #endif
- rsferrno = ESFWRERR;
- rsferrstr = "write error truncating file";
- return -1;
- }
- }
- return 0;
- }
- int
- sfclose(int sfd)
- {
- struct sf_file *f;
- int rc = 0;
- if((f = findfile(sfd)) == 0){ //RWD: may already have been closed... see errrmsg
- rsferrstr = "SFSYS: close: bad file ID (already closed?)";
- return -1;
- }
- #ifdef ENABLE_PVX
- if(f->pvxprops != NULL){
- //either readonly input file, or new output file. If latter, must fill in analysis fields from sfprops
- //including fmtx
- //set pvxdata first, then set wfmt from that
- if(!f->readonly) {
- int origsize = 0,origrate=0,winlen=0,decfac=0;
- float arate = 0.0;
- int res;
- //sfgetprop(int sfd, const char *propname, char *dest, int lim)
- # ifdef _DEBUG
- assert(f->pvxprops->nAnalysisBins > 0);
- # endif
- //ERROR! for pvx we want to get this from Format.wBitsPerSample
- res = sfgetprop(sfd,"original sampsize",(char*) &origsize,sizeof(int));
- if(res < 0){
- # ifdef _DEBUG
- fprintf(stderr,"error from sfgetprop: original sampsize\n");
- # endif
- return -1;
- }
- else
- // fprintf(stderr, "sfclose: got original sampsize = %d\n",origsize);
-
-
- res = sfgetprop(sfd,"original sample rate",(char*) &origrate,sizeof(int));
- if(res < 0){
- // fprintf(stderr,"error from sfgetprop: original samplerate\n");
- return -1;
- }
- else
- // fprintf(stderr, "sfclose: got original sample rate = %d\n",origrate);
- res = sfgetprop(sfd,"arate",(char*) &arate,sizeof(float));
- if(res < 0){
- // fprintf(stderr,"error from sfgetprop: arate\n");
- return -1;
- }
- else
- // fprintf(stderr, "sfclose: got arate = %f\n",arate);
-
- res = sfgetprop(sfd,"analwinlen",(char*) &winlen,sizeof(int));
- res = sfgetprop(sfd,"decfactor",(char*) &decfac,sizeof(int));
-
- //this comes from dz->infile->stype
-
- switch(origsize){
- case SAMP_SHORT:
- f->fmtchunkEx.Format.wBitsPerSample = 16;
- break;
- case SAMP_2024:
- case SAMP_2424:
- f->fmtchunkEx.Format.wBitsPerSample = 24;
- break;
- case SAMP_LONG:
- case SAMP_FLOAT:
- f->fmtchunkEx.Format.wBitsPerSample = 32;
- }
-
- f->pvxprops->wWordFormat = PVOC_IEEE_FLOAT; /* no plans for a doubles implementation yet */
- f->pvxprops->wAnalFormat = PVOC_AMP_FREQ;
- f->pvxprops->wSourceFormat = origsize == SAMP_FLOAT ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM;
- f->pvxprops->wWindowType = /* probably*/ PVOC_HANN; /* whatever is set in CDP pvoc these days */
- f->pvxprops->fAnalysisRate = arate;
- /* we already have nAnalysisBins, can't change that anyway */
- f->pvxprops->dwWinlen = winlen;
- f->pvxprops->dwOverlap = decfac;
- f->fmtchunkEx.Format.nSamplesPerSec = origrate;
- f->fmtchunkEx.Format.nChannels = 1;
- // f->fmtchunkEx.Format.wBitsPerSample = 32;
- f->fmtchunkEx.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
- f->fmtchunkEx.Format.nBlockAlign = f->fmtchunkEx.Format.nChannels * sizeof(float);
- f->fmtchunkEx.Format.nAvgBytesPerSec =f->fmtchunkEx.Format.nBlockAlign * f->fmtchunkEx.Format.nSamplesPerSec;
- f->fmtchunkEx.Format.cbSize = 62;
- f->filetype = riffwav;
- }
-
- if((rc = pvoc_update_closefile(f->pvxfileno,f->pvxprops,&f->fmtchunkEx)) < 0){
- #ifdef _DEBUG
- fprintf(stderr,"sfclose: can't close pvx file\n");
- #endif
- return -1;
- }
- else {
- // fprintf(stderr,"pvx file closed OK!\n");
- freesffile(sfd-SFDBASE);
- }
- return rc;
- }
- /* RWD TODO: handle f->todelete, typically set by call to sfunlink(sfd) */
- #endif
- if((f->infochanged || f->propschanged) && !f->todelete && !f->readonly) {
- unsigned int cdptime;
- time_t now = time(0);
- cdptime = (unsigned int) now;
- //RWD.5.99
- if((f->min_header >= SFILE_CDP) && POS64(f->propoffset) > 0)
- sfputprop(sfd, "DATE", /* (char *)&now */ (char *) &cdptime, sizeof(/*long*/int));
- switch(f->filetype) {
- case riffwav:
- case wave_ex:
- if(f->header_set)
- rc = wavupdate98(now,f); //RWD.6.5.99
- else
- rc = wavupdate(f);
- break;
- case eaaiff:
- case aiffc:
- if(f->header_set)
- rc = aiffupdate98(now,f);
- else
- rc = aiffupdate(now,f); //RWD.6.5.99
- break;
- default:
- //abort();
- rsferrno = ESFBADPARAM;
- rsferrstr = "SFSYS98: aif-c files not supported";
- return -1;
- break;
- }
- f->propschanged = 1;
- }
- if(f->min_header >= SFILE_CDP && POS64(f->propoffset) >= 0 && f->propschanged && !f->todelete && !f->readonly)
- if(writeprops(f) < 0)
- rc = -1;
- #if defined _WIN32
- if(!CloseHandle(f->fileno)) {
- #else
- if(fclose(f->fileno) < 0) {
- #endif
- rsferrno = ESFWRERR;
- rsferrstr = "write error: system had trouble closing file";
- rc = -1;
- }
- if(f->todelete
- && f->filename != NULL
- #if defined _WIN32
- && !DeleteFile(f->filename)){
- #else
- && remove(f->filename) < 0) {
- #endif
- rsferrno = ESFWRERR;
- rsferrstr = "can't remove soundfile";
- rc = -1;
- }
- freesffile(sfd-SFDBASE);
- return rc;
- }
- //return true size in bytes: of SHORTS or FLOATS file
- __int64
- sfsize(int sfd)
- {
- struct sf_file *f;
- if((f = findfile(sfd)) == 0)
- return -1;
- return (__int64)(f->sizerequested == ES_EXIST ? f->datachunksize : f->sizerequested);
- }
- #ifdef FILE64_WIN
- int
- sfadjust(int sfd, __int64 delta)
- {
- struct sf_file *f;
- __int64 newsize;
- if(delta > 0) {
- rsferrno = ESFBADPARAM;
- rsferrstr = "Can't extend a soundfile";
- return -1;
- }
- if((f = findfile(sfd)) == 0)
- return -1;
- if(f->readonly) {
- rsferrno = ESFREADONLY;
- rsferrstr = "can't adjust size of read-only file";
- return -1;
- }
- f->infochanged = 1;
- switch(f->sizerequested) {
- case ES_EXIST:
- if(f->datachunksize + delta < 0) {
- rsferrno = ESFBADPARAM;
- rsferrstr = "can't make soundfile with negative size";
- return -1;
- }
- f->datachunksize += delta;
- break;
- default:
- if(f->sizerequested + delta < 0) {
- rsferrno = ESFBADPARAM;
- rsferrstr = "can't make soundfile with negative size";
- return -1;
- }
- if(f->sizerequested + delta >= f->datachunksize)
- return 0;
- f->sizerequested += delta;
- f->datachunksize = f->sizerequested;
- break;
- }
- newsize = f->datachunkoffset;
- if(f->fmtchunkEx.Format.wBitsPerSample == 8)
- newsize += f->datachunksize/2;
- else
- newsize += f->datachunksize;
- #if defined _WIN32
- if(w_ch_size(f->fileno, newsize) < 0) {
- #else
- if(chsize(f->fileno, newsize) < 0) {
- #endif
- rsferrno = ESFWRERR;
- rsferrstr = "write error truncating file";
- return -1;
- }
- return 0; /* is this right? */
- }
- #else
- int
- sfadjust(int sfd, __int64 delta)
- {
- struct sf_file *f;
- __int64 newsize;
- if(delta > 0) {
- rsferrno = ESFBADPARAM;
- rsferrstr = "Can't extend a soundfile";
- return -1;
- }
- if((f = findfile(sfd)) == 0)
- return -1;
- if(f->readonly) {
- rsferrno = ESFREADONLY;
- rsferrstr = "can't adjust size of read-only file";
- return -1;
- }
- f->infochanged = 1;
- switch(f->sizerequested) {
- case ES_EXIST:
- if( f->datachunksize + delta < 0) {
- rsferrno = ESFBADPARAM;
- rsferrstr = "can't make soundfile with negative size";
- return -1;
- }
- f->datachunksize += delta;
- break;
- default:
- if(f->sizerequested + delta < 0) {
- rsferrno = ESFBADPARAM;
- rsferrstr = "can't make soundfile with negative size";
- return -1;
- }
- if(f->sizerequested + delta >= f->datachunksize)
- return 0;
- f->sizerequested += delta;
- f->datachunksize = f->sizerequested;
- break;
- }
- newsize = (__int64) POS64(f->datachunkoffset);
- if(f->fmtchunkEx.Format.wBitsPerSample == 8)
- newsize += f->datachunksize/2;
- else
- newsize += f->datachunksize;
- #if defined _WIN32
- if(w_ch_size(f->fileno, newsize) < 0) {
- #else
- if(chsize(fileno(f->fileno), newsize) < 0) {
- #endif
- rsferrno = ESFWRERR;
- rsferrstr = "write error truncating file";
- return -1;
- }
- return 0; /* is this right? */
- }
- #endif
- int
- sfunlink(int sfd)
- {
- struct sf_file *f;
- if((f = findfile(sfd)) == 0)
- return -1;
- if(f->readonly) {
- rsferrno = ESFREADONLY;
- rsferrstr = "can't delete read-only file";
- return -1;
- }
- f->todelete = 1;
- return 0;
- }
- int
- sfrename(int sfd, const char *newname)
- {
- struct sf_file *f;
- char *path = NULL;
- if((f = findfile(sfd)) == 0)
- return -1;
- if(f->readonly) {
- rsferrno = ESFREADONLY;
- rsferrstr = "can't rename read-only file";
- return -1;
- }
- if(f->filename == 0) {
- rsferrno = ESFNOMEM;
- rsferrstr = "Couldn't remember name of file";
- return -1;
- }
- path = mksfpath(newname);
- if(path==NULL){
- rsferrno = ESFBADPARAM;
- rsferrstr = "can't rename file changing its type";
- return -1;
- }
- if(f->filetype != gettypefromname98(path)) {
- rsferrno = ESFBADPARAM;
- rsferrstr = "can't rename file changing its type";
- return -1;
- }
- if(rename(f->filename, path) != 0) {
- rsferrno = ESFDUPFNAME;
- rsferrstr = "file already exists, or can't rename across devices";
- return -1;
- }
- free(f->filename);
- f->filename = _fullpath(NULL, path, 0);
- return 0;
- }
- /*
- * Property access routines
- */
- //RWD.6.99 mega-special case for sample type now!
- int
- sfgetprop(int sfd, const char *propname, char *dest, int lim)
- {
- int lret = SAMP_MASKED; //RWD.6.99
- int res,containersize;
- struct sf_file *f;
- struct property *pp;
- if((f = findfile(sfd)) == 0)
- return -1;
- if(strcmp(propname, "channels") == 0)
- lret = f->fmtchunkEx.Format.nChannels;
- else if(strcmp(propname, "sample rate") == 0)
- lret = f->fmtchunkEx.Format.nSamplesPerSec;
- else if(strcmp(propname, "sample type") == 0) {
- //RWD.6.99 lets accept all formats!
- //is this good for AIFF?
- containersize = 8 * (f->fmtchunkEx.Format.nBlockAlign / f->fmtchunkEx.Format.nChannels);
- switch(containersize){
- case(32):
- if(f->fmtchunkEx.Format.wFormatTag== WAVE_FORMAT_IEEE_FLOAT
- || (f->fmtchunkEx.Format.wFormatTag == WAVE_FORMAT_EXTENSIBLE
- && (
- (compare_guids(&(f->fmtchunkEx.SubFormat),&(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)))
- ||
- (compare_guids(&(f->fmtchunkEx.SubFormat),&(SUBTYPE_AMBISONIC_B_FORMAT_IEEE_FLOAT)))
- )
- )
- ) {
- lret = SAMP_FLOAT;
- break;
- }
- else{
- //int format: may be masked
- switch(f->fmtchunkEx.Samples.wValidBitsPerSample){
- case(32):
- lret = SAMP_LONG;
- break;
- case(24):
- lret = SAMP_2432;
- break;
- default:
- lret = SAMP_MASKED;
- break;
- }
- }
- break;
- case(24):
- switch(f->fmtchunkEx.Samples.wValidBitsPerSample){
- case(24):
- lret = SAMP_2424;
- break;
- case(20):
- lret = SAMP_2024;
- break;
- default:
- lret = SAMP_MASKED;
- break;
- }
- break;
- case(16):
- case(8):
- lret = SAMP_SHORT;
- break;
- default:
- break;
- }
- } else {
- if(f->min_header < SFILE_CDP){
- rsferrno = ESFNOTFOUND;
- rsferrstr = "no CDP properties in minimum header";
- return -1;
- }
- if(POS64(f->propoffset) >= 0)
- for(pp = f->props; pp != 0; pp = pp->next) {
- if(strcmp(propname, pp->name) == 0) {
- res = min(pp->size, lim);
- memcpy(dest, pp->data, res);
- #ifdef ENABLE_PVX
- # ifdef _DEBUG
- // fprintf(stderr,"sfgetprop: found prop %s\n",propname);
- # endif
- #endif
- return res;
- }
- }
- rsferrno = ESFNOTFOUND;
- rsferrstr = "Property not defined in file";
- #ifdef ENABLE_PVX
- # ifdef _DEBUG
- // fprintf(stderr,"failed to find property %s, propoffset = %lld\n",propname,POS64(f->propoffset));
- # endif
- #endif
- return -1;
- }
- /*
- * return a standard property as a long
- */
- res = min(lim, sizeof(int));
- memcpy(dest, &lret, res);
- return res;
- }
- static int
- getlong(int *dest, char *src, int size, int error)
- {
- if(size != sizeof(int)) {
- rsferrno = error;
- rsferrstr = "Bad size for standard property";
- return -1;
- }
- memcpy(dest, src, sizeof(int));
- return 0;
- }
- //RWD.6.99 trap attempts to update primary properties of streamable file
- // ATARI trapped, but ATARI ~could~ support 32bit longs, but who cares?
- int
- sfputprop(int sfd, char *propname, char *src, int size)
- {
- int data;
- struct sf_file *f;
- struct property *pp, **ppp;
- char *np;
-
- if((f = findfile(sfd)) == 0)
- return -1;
- if(f->readonly) {
- rsferrno = ESFREADONLY;
- rsferrstr = "can't set property in a read-only file";
- return -1;
- }
-
- if(strcmp(propname, "channels") == 0) {
- if(getlong(&data, src, size, ESFBADNCHANS) < 0)
- return -1;
- //RWD.6.99
- if(f->header_set && (data != (int)f->fmtchunkEx.Format.nChannels)){
- rsferrno = ESFBADPARAM;
- rsferrstr = "not allowed to alter existing property";
- return -1;
-
- }
- f->fmtchunkEx.Format.nChannels = (short)data;
- f->infochanged = 1;
- return 0;
- } else if(strcmp(propname, "sample rate") == 0) {
-
- if(getlong(&data, src, size, ESFBADRATE) < 0)
- return -1;
- //RWD.6.99
- if(f->header_set && (data != (int) f->fmtchunkEx.Format.nSamplesPerSec)){
- rsferrno = ESFBADPARAM;
- rsferrstr = "not allowed to alter existing property";
- return -1;
- }
- f->fmtchunkEx.Format.nSamplesPerSec = data;
- f->infochanged = 1;
- return 0;
- } else if(strcmp(propname, "sample type") == 0) {
- if(f->header_set){
- rsferrno = ESFBADPARAM;
- rsferrstr = "not allowed to alter existing property";
- return -1;
- }
- if(getlong(&data, src, size, ESFBADPARAM) < 0)
- return -1;
-
- if(data < SAMP_SHORT && data >= SAMP_MASKED) {
- rsferrno = ESFBADPARAM;
- rsferrstr = "cannot change to unsupported sample type";
- return -1;
- }
-
- if(f->fmtchunkEx.Format.wBitsPerSample == 8) {
- rsferrno = ESFBADPARAM;
- rsferrstr = "Can't change sample type when accessing 8 bits/sample file";
- return -1;
- }
-
- switch(data){
- case(SAMP_LONG):
- case(SAMP_FLOAT):
- case(SAMP_2432):
- f->fmtchunkEx.Format.wBitsPerSample = 32;
- break;
- case(SAMP_2424):
- case(SAMP_2024):
- f->fmtchunkEx.Format.wBitsPerSample = 24;
- break;
- case(SAMP_SHORT):
- f->fmtchunkEx.Format.wBitsPerSample = 16;
- break;
- case(SAMP_BYTE):
- rsferrno = ESFBADPARAM;
- rsferrstr = "8-bit files not supported for writing";
- return -1;
- default:
- rsferrno = ESFBADPARAM;
- rsferrstr = "cannot set unsupported sample type";
- return -1;
- break;
-
- }
- f->infochanged = 1;
- return 0;
- }
-
- /*
- * now deal with extended attributes
- */
-
- if((f->min_header < SFILE_CDP) || POS64(f->propoffset) < 0) {
- rsferrno = ESFNOSPACE;
- rsferrstr = "No property chunk in this .wav file";
- return -1;
- }
-
- for(pp = f->props; pp != 0; pp = pp->next) {
- if(strcmp(propname, pp->name) == 0) {
- if(f->curpropsize + 2*(size - pp->size) > f->proplim) {
- rsferrno = ESFNOSPACE;
- rsferrstr = "No space in extended properties for bigger property data";
- return -1;
- }
- if((np = (char *) malloc(size)) == 0) {
- rsferrno = ESFNOMEM;
- rsferrstr = "No memory for bigger property data";
- return -1;
- }
- memcpy(np, src, size);
- free(pp->data);
- pp->data = np;
- pp->size = size;
- f->curpropsize -= 2*(size - pp->size);
- f->propschanged = 1;
- return 0;
- }
- }
-
- /* adding new property */
- if(f->curpropsize + (signed int)strlen(propname) + 2 + 2*size > f->proplim) {
- rsferrno = ESFNOSPACE;
- rsferrstr = "No space in extended properties for new property data";
- return -1;
- }
- for(ppp = &f->props; *ppp != 0; ppp = &(*ppp)->next)
- ;
- if((*ppp = ALLOC(struct property)) == 0
- ||((*ppp)->name = (char *) malloc(strlen(propname)+1)) == 0
- ||((*ppp)->data = (char *) malloc(size)) == 0) {
- rsferrno = ESFNOMEM;
- rsferrstr = "No memory for bigger property data";
- return -1;
- }
- strcpy((*ppp)->name, propname);
- memcpy((*ppp)->data, src, size);
- (*ppp)->size = size;
- (*ppp)->next = 0;
- f->curpropsize += strlen(propname) + 2 + 2*size;
- f->propschanged = 1;
- return 0;
- }
- //RWD.6.5.99 not used internally by header routines, return 0 for true
- int sfputpeaks(int sfd,int channels,const CHPEAK peakdata[])
- {
- int i;
- struct sf_file *f;
-
- if((f = findfile(sfd)) == 0)
- return -1;
- if(f->readonly) {
- rsferrno = ESFREADONLY;
- rsferrstr = "can't set property in a read-only file";
- return -1;
- }
-
- if(f->min_header < SFILE_PEAKONLY){
- rsferrno = ESFNOSPACE;
- rsferrstr = "no space for peak data in minimum header";
- return -1;
-
-
- }
-
- if(f->peaks==NULL){
- rsferrno = ESFREADONLY;
- rsferrstr = "peak data not initialized";
- return -1;
-
- }
- for(i=0;i < channels; i++){
- f->peaks[i].value = peakdata[i].value;
- f->peaks[i].position = peakdata[i].position;
- }
- return 0;
- }
- //NB this one not used internally by header routines, return 1 for true
- int sfreadpeaks(int sfd,int channels,CHPEAK peakdata[],int *peaktime)
- {
- int i;
- struct sf_file *f;
- if((f = findfile(sfd)) == 0)
- return -1;
- if(f->peaks==NULL){ //NOT an error: just don't have the chunk
- *peaktime = 0;
- return 0;
- }
- *peaktime = (int) f->peaktime;
- for(i=0;i < channels; i++){
- peakdata[i].value = f->peaks[i].value;
- peakdata[i].position = f->peaks[i].position;
- }
- return 1;
- }
- int
- sfrmprop(int sfd, char *propname)
- {
- struct sf_file *f;
- struct property **ppp;
- if((f = findfile(sfd)) == 0)
- return -1;
- if(f->readonly) {
- rsferrno = ESFREADONLY;
- rsferrstr = "can't remove property from a read-only file";
- return -1;
- }
- if(strcmp(propname, "channels") == 0
- ||strcmp(propname, "sample rate") == 0
- ||strcmp(propname, "sample type") == 0) {
- rsferrno = ESFBADPARAM;
- rsferrstr = "Cannot remove standard property";
- return -1;
- }
- if(f->min_header < SFILE_CDP){
- rsferrno = ESFNOTFOUND;
- rsferrstr = "minimum header - no CDP properties present";
- return -1;
- }
- if(POS64(f->propoffset) >= 0)
- for(ppp = &f->props; *ppp != 0; ppp = &(*ppp)->next)
- if(strcmp((*ppp)->name, propname) == 0) {
- struct property *p = *ppp;
- f->curpropsize -= strlen(propname) + 2 + p->size;
- f->propschanged = 1;
- free(p->name);
- free(p->data);
- *ppp = p->next;
- free(p);
- return 0;
- }
- rsferrno = ESFNOTFOUND;
- rsferrstr = "Property not found";
- return -1;
- }
- int
- sfdirprop(int sfd, int (*func)(char *propname, int propsize))
- {
- struct sf_file *f;
- struct property *pp;
- if((f = findfile(sfd)) == 0)
- return -1;
- if(func("channels", sizeof( int)) != 0
- ||func("sample type", sizeof( int)) != 0
- ||func("sample rate", sizeof( int)) != 0)
- return SFDIR_FOUND;
- for(pp = f->props; pp != 0; pp = pp->next)
- if(func(pp->name, pp->size) != 0)
- return SFDIR_FOUND;
- return SFDIR_NOTFOUND;
- }
- //CDP98
- #if defined _WIN32 && defined _MSC_VER
- static int asm_round(double fval)
- {
- int result;
- _asm{
- fld fval
- fistp result
- mov eax,result
- }
- return (long) result;
- }
- #endif
-
- int cdp_round(double fval)
- {
- #if defined _WIN32 && defined _MSC_VER
- return asm_round(fval);
- #elseif defined unix
- return (int) lround(fval);
- #else
- int k;
- k = (int)(fabs(fval)+0.5);
- if(fval < 0.0)
- k = -k;
- return k;
- #endif
- }
- int sfformat(int sfd, fileformat *pfmt)
- {
- struct sf_file *f;
- if(pfmt==NULL)
- return 0;
- if((f = findfile(sfd)) == 0)
- return -1;
- if(f->filetype == riffwav)
- *pfmt = WAVE;
- else if(f->filetype == wave_ex)
- *pfmt = WAVE_EX;
- else if(f->filetype== eaaiff)
- *pfmt = AIFF;
- else if(f->filetype ==aiffc)
- *pfmt = AIFC;
- #ifdef ENABLE_PVX
- else if(f->filetype == pvxfile)
- *pfmt = PVOCEX;
- #endif
- else
- return -1;
- return 0;
- }
- int sfgetchanmask(int sfd)
- {
- struct sf_file *f;
- //int mask = 0; //default is generic (unassigned)
- if((f = findfile(sfd)) ==NULL)
- return -1;
- if(f->filetype==wave_ex)
- return f->fmtchunkEx.dwChannelMask;
- return 0;
- }
- //private, but used by sndsystem
- int _rsf_getbitmask(int sfd)
- {
- struct sf_file *f;
- if((f = findfile(sfd)) ==NULL)
- return 0;
- return f->bitmask;
- }
- int sf_getchanformat(int sfd, channelformat *chformat)
- {
- struct sf_file *f;
- if((f = findfile(sfd)) ==NULL)
- return -1;
- if(chformat==NULL)
- return -1;
- *chformat = f->chformat;
- return 0;
- }
- const char* sf_getfilename(int sfd)
- {
- struct sf_file *f;
- if((f = findfile(sfd)) ==NULL)
- return NULL;
- return (const char *) f->filename;
- }
- int sf_getcontainersize(int sfd)
- {
- struct sf_file *f;
- if((f = findfile(sfd)) ==NULL)
- return -1;
- return (int) f->fmtchunkEx.Format.wBitsPerSample;
- }
- int sf_getvalidbits(int sfd)
- {
- struct sf_file *f;
- if((f = findfile(sfd)) ==NULL)
- return -1;
- return (int) f->fmtchunkEx.Samples.wValidBitsPerSample;
- }
- //keep this as private func for now, but used by snd routines
- // may have pos >2GB so need unsigned retval
- unsigned int _rsf_getmaxpeak(int sfd,float *peak)
- {
- struct sf_file *f;
- int i;
- double peakval = 0.0;
- if((f = findfile(sfd)) ==NULL)
- return 0xFFFFFFFF;
- if(f->peaks == NULL)
- return 0;
- for(i=0; i < f->fmtchunkEx.Format.nChannels; i++)
- peakval = max(peakval,(double)(f->peaks[i].value));
- *peak = (float) peakval;
- return 1;
- }
- int addprop(struct sf_file *f, char *propname, char *src, int size)
- {
- struct property /* *pp,*/ **ppp;
- /*char *np;*/
- if(f->curpropsize + (signed int)strlen(propname) + 2 + 2*size > f->proplim) {
- rsferrno = ESFNOSPACE;
- rsferrstr = "No space in extended properties for new property data";
- return -1;
- }
- for(ppp = &f->props; *ppp != 0; ppp = &(*ppp)->next)
- ;
- if((*ppp = ALLOC(struct property)) == 0
- ||((*ppp)->name = (char *) malloc(strlen(propname)+1)) == 0
- ||((*ppp)->data = (char *) malloc(size)) == 0) {
- rsferrno = ESFNOMEM;
- rsferrstr = "No memory for bigger property data";
- return -1;
- }
- strcpy((*ppp)->name, propname);
- memcpy((*ppp)->data, src, size);
- (*ppp)->size = size;
- (*ppp)->next = 0;
- f->curpropsize += strlen(propname) + 2 + 2*size;
- f->propschanged = 1;
- return 0;
- }
- #ifdef ENABLE_PVX
- //pvxprops to sfsys props
- static int writefirstprop(struct sf_file *f, char *propname, char *src, int size)
- {
- struct property /* *pp,*/ **ppp;
-
- ppp = &f->props;
- if((*ppp = ALLOC(struct property)) == 0
- ||((*ppp)->name = (char *) malloc(strlen(propname)+1)) == 0
- ||((*ppp)->data = (char *) malloc(size)) == 0) {
- rsferrno = ESFNOMEM;
- rsferrstr = "No memory for bigger property data";
- return -1;
- }
- strcpy((*ppp)->name, propname);
- memcpy((*ppp)->data, src, size);
- (*ppp)->size = size;
- (*ppp)->next = 0;
- f->curpropsize += strlen(propname) + 2 + 2*size;
- f->proplim = 1000; // RWD completely arbitrary!
- // f->propschanged = 1; // because this is a quasi-creation of ana file
- return 0;
- }
- #endif
-
-
- /* required mapping:
- PVX ----------> ANA
- nAnalysisBins N... *2 = props.chans
- overlap decfac
- format=PVOC_AMP_FREQ [no field - always this format, have to reject other type of pvx file]
- srate origrate
- arate arate AND (int) WAV srate
- */
- #ifdef ENABLE_PVX
- /* may as well set all props here, including basic ones from WAVFORMATEX */
- static int pvx_createprops(struct sf_file *f) {
- struct property **ppp = &f->props;
- sampletype samptype;
- unsigned int origsize, origrate, winlen,decfac,analchans;
- float arate;
- #ifdef _DEBUG
- assert(f->curpropsize ==0);
- assert(f->pvxprops != NULL);
- /* NB oddity of CDP ana format - sets WAV sample rate as (int) analysis rate,
- as shown by dirsf */
- // assert(f->fmtchunkEx.Format.nSamplesPerSec == 0);
- #endif
- /* map pvx props to .ana props - not all are identical */
- if(f->pvxprops->wSourceFormat==WAVE_FORMAT_IEEE_FLOAT)
- samptype = FLOAT32;
- else {
- switch(f->fmtchunkEx.Format.wBitsPerSample){
- case 24:
- samptype = INT2424; /* can't represent INT2432 in anaprops) */
- break;
- case 32:
- samptype = INT_32;
- break;
- default:
- samptype = SHORT16;
- break;
- }
- }
- /* next, we have to convert Format into apparent floatsam file...*/
-
- analchans = f->pvxprops->nAnalysisBins * 2;
- origsize = (unsigned int) samptype;
- origrate = f->fmtchunkEx.Format.nSamplesPerSec;
- decfac = f->pvxprops->dwWinlen;
- arate = f->pvxprops->fAnalysisRate;
- winlen = f->pvxprops->dwWinlen;
- decfac = f->pvxprops->dwOverlap;
-
- /* set all WAV fornat fields as an .ana file would do... */
- // TODO: allocate and populate char* memory block for proerties, as if getting props block from file
- // call parseprops to load into f->props
-
- // have to make first prop entry explicitly, then can call addprop for the rest
- if(writefirstprop(f,"original sampsize",(char*) & origsize, sizeof(int)) < 0) {
- rsferrstr = "Failure to write original sample size";
- return -1;
- }
- if(addprop(f,"original sample rate",(char *)&origrate,sizeof(int))<0){
- rsferrstr = "Failure to write original sample rate";
- return -1;
- }
- if(addprop(f,"arate",(char *) &arate,sizeof(float)) < 0){
- rsferrstr = "Failure to write analysis sample rate";
- return -1;
- }
- if(addprop(f,"analwinlen",(char *)& winlen,sizeof(int)) < 0){
- rsferrstr = "Failure to write analysis window length";
- return -1;
- }
- if(addprop(f,"decfactor",(char *)& decfac,sizeof(int)) < 0){
- rsferrstr = "Failure to write decimation factor";
- return -1;
- }
- #ifdef _DEBUG
- // fprintf(stderr, "added all ana properties OK\n");
- #endif
- f->propschanged = 0; // see above: first creation of quasi-ana data
- return 0;
- }
- #endif
-
- // not used yet...
- #ifdef ENABLE_PVX
- static int sfprops2pvx(struct sf_file *f)
- {
- struct property **ppp = &f->props;
- sampletype samptype;
- unsigned int origsize, origrate, winlen,decfac,analchans;
- float arate;
- #ifdef _DEBUG
- assert(f->curpropsize != 0);
- assert(f->pvxprops != NULL);
- assert(f->pvxfileno >=0);
- #endif
- return 0;
- }
- #endif
- int sf_makepath(char path[], const char* sfname)
- {
- char* fullname = mksfpath(sfname);
- if(fullname==NULL)
- return -1;
- strcpy(path,fullname);
- return 0;
- }
|