| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082 |
- /* 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
- #ifdef __GLIBC__
- #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
- // RWD For WIN32, link with ksuser.dll
- 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?
- //RWD 2025 fix this for pvx file with large fft size
- //possible TODO: for analysis files, report src sample type, not just 'float'
- if (f->filetype == pvxfile) {
- containersize = sf_getcontainersize(sfd);
- }
- else {
- 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 0
- static int asm_round(double fval)
- {
- int result;
- _asm{
- fld fval
- fistp result
- mov eax,result
- }
- return (long) result;
- }
- #endif
- //RWD don't need this any more. "Deprecated".
- int cdp_round(double fval)
- {
- return lround(fval);
- }
- 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;
- }
|