wavesurfer.js 195 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248
  1. /*!
  2. * wavesurfer.js 4.1.1 (2020-09-25)
  3. * https://wavesurfer-js.org
  4. * @license BSD-3-Clause
  5. */
  6. (function webpackUniversalModuleDefinition(root, factory) {
  7. if(typeof exports === 'object' && typeof module === 'object')
  8. module.exports = factory();
  9. else if(typeof define === 'function' && define.amd)
  10. define("WaveSurfer", [], factory);
  11. else if(typeof exports === 'object')
  12. exports["WaveSurfer"] = factory();
  13. else
  14. root["WaveSurfer"] = factory();
  15. })(this, function() {
  16. return /******/ (function(modules) { // webpackBootstrap
  17. /******/ // The module cache
  18. /******/ var installedModules = {};
  19. /******/
  20. /******/ // The require function
  21. /******/ function __webpack_require__(moduleId) {
  22. /******/
  23. /******/ // Check if module is in cache
  24. /******/ if(installedModules[moduleId]) {
  25. /******/ return installedModules[moduleId].exports;
  26. /******/ }
  27. /******/ // Create a new module (and put it into the cache)
  28. /******/ var module = installedModules[moduleId] = {
  29. /******/ i: moduleId,
  30. /******/ l: false,
  31. /******/ exports: {}
  32. /******/ };
  33. /******/
  34. /******/ // Execute the module function
  35. /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
  36. /******/
  37. /******/ // Flag the module as loaded
  38. /******/ module.l = true;
  39. /******/
  40. /******/ // Return the exports of the module
  41. /******/ return module.exports;
  42. /******/ }
  43. /******/
  44. /******/
  45. /******/ // expose the modules object (__webpack_modules__)
  46. /******/ __webpack_require__.m = modules;
  47. /******/
  48. /******/ // expose the module cache
  49. /******/ __webpack_require__.c = installedModules;
  50. /******/
  51. /******/ // define getter function for harmony exports
  52. /******/ __webpack_require__.d = function(exports, name, getter) {
  53. /******/ if(!__webpack_require__.o(exports, name)) {
  54. /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
  55. /******/ }
  56. /******/ };
  57. /******/
  58. /******/ // define __esModule on exports
  59. /******/ __webpack_require__.r = function(exports) {
  60. /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
  61. /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
  62. /******/ }
  63. /******/ Object.defineProperty(exports, '__esModule', { value: true });
  64. /******/ };
  65. /******/
  66. /******/ // create a fake namespace object
  67. /******/ // mode & 1: value is a module id, require it
  68. /******/ // mode & 2: merge all properties of value into the ns
  69. /******/ // mode & 4: return value when already ns object
  70. /******/ // mode & 8|1: behave like require
  71. /******/ __webpack_require__.t = function(value, mode) {
  72. /******/ if(mode & 1) value = __webpack_require__(value);
  73. /******/ if(mode & 8) return value;
  74. /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
  75. /******/ var ns = Object.create(null);
  76. /******/ __webpack_require__.r(ns);
  77. /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
  78. /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
  79. /******/ return ns;
  80. /******/ };
  81. /******/
  82. /******/ // getDefaultExport function for compatibility with non-harmony modules
  83. /******/ __webpack_require__.n = function(module) {
  84. /******/ var getter = module && module.__esModule ?
  85. /******/ function getDefault() { return module['default']; } :
  86. /******/ function getModuleExports() { return module; };
  87. /******/ __webpack_require__.d(getter, 'a', getter);
  88. /******/ return getter;
  89. /******/ };
  90. /******/
  91. /******/ // Object.prototype.hasOwnProperty.call
  92. /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
  93. /******/
  94. /******/ // __webpack_public_path__
  95. /******/ __webpack_require__.p = "";
  96. /******/
  97. /******/
  98. /******/ // Load entry module and return exports
  99. /******/ return __webpack_require__(__webpack_require__.s = "./src/wavesurfer.js");
  100. /******/ })
  101. /************************************************************************/
  102. /******/ ({
  103. /***/ "./node_modules/debounce/index.js":
  104. /*!****************************************!*\
  105. !*** ./node_modules/debounce/index.js ***!
  106. \****************************************/
  107. /*! no static exports found */
  108. /***/ (function(module, exports) {
  109. /**
  110. * Returns a function, that, as long as it continues to be invoked, will not
  111. * be triggered. The function will be called after it stops being called for
  112. * N milliseconds. If `immediate` is passed, trigger the function on the
  113. * leading edge, instead of the trailing. The function also has a property 'clear'
  114. * that is a function which will clear the timer to prevent previously scheduled executions.
  115. *
  116. * @source underscore.js
  117. * @see http://unscriptable.com/2009/03/20/debouncing-javascript-methods/
  118. * @param {Function} function to wrap
  119. * @param {Number} timeout in ms (`100`)
  120. * @param {Boolean} whether to execute at the beginning (`false`)
  121. * @api public
  122. */
  123. function debounce(func, wait, immediate){
  124. var timeout, args, context, timestamp, result;
  125. if (null == wait) wait = 100;
  126. function later() {
  127. var last = Date.now() - timestamp;
  128. if (last < wait && last >= 0) {
  129. timeout = setTimeout(later, wait - last);
  130. } else {
  131. timeout = null;
  132. if (!immediate) {
  133. result = func.apply(context, args);
  134. context = args = null;
  135. }
  136. }
  137. };
  138. var debounced = function(){
  139. context = this;
  140. args = arguments;
  141. timestamp = Date.now();
  142. var callNow = immediate && !timeout;
  143. if (!timeout) timeout = setTimeout(later, wait);
  144. if (callNow) {
  145. result = func.apply(context, args);
  146. context = args = null;
  147. }
  148. return result;
  149. };
  150. debounced.clear = function() {
  151. if (timeout) {
  152. clearTimeout(timeout);
  153. timeout = null;
  154. }
  155. };
  156. debounced.flush = function() {
  157. if (timeout) {
  158. result = func.apply(context, args);
  159. context = args = null;
  160. clearTimeout(timeout);
  161. timeout = null;
  162. }
  163. };
  164. return debounced;
  165. };
  166. // Adds compatibility for ES modules
  167. debounce.debounce = debounce;
  168. module.exports = debounce;
  169. /***/ }),
  170. /***/ "./src/drawer.canvasentry.js":
  171. /*!***********************************!*\
  172. !*** ./src/drawer.canvasentry.js ***!
  173. \***********************************/
  174. /*! no static exports found */
  175. /***/ (function(module, exports, __webpack_require__) {
  176. "use strict";
  177. Object.defineProperty(exports, "__esModule", {
  178. value: true
  179. });
  180. exports.default = void 0;
  181. var _style = _interopRequireDefault(__webpack_require__(/*! ./util/style */ "./src/util/style.js"));
  182. var _getId = _interopRequireDefault(__webpack_require__(/*! ./util/get-id */ "./src/util/get-id.js"));
  183. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  184. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  185. function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
  186. function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
  187. /**
  188. * The `CanvasEntry` class represents an element consisting of a wave `canvas`
  189. * and an (optional) progress wave `canvas`.
  190. *
  191. * The `MultiCanvas` renderer uses one or more `CanvasEntry` instances to
  192. * render a waveform, depending on the zoom level.
  193. */
  194. var CanvasEntry = /*#__PURE__*/function () {
  195. function CanvasEntry() {
  196. _classCallCheck(this, CanvasEntry);
  197. /**
  198. * The wave node
  199. *
  200. * @type {HTMLCanvasElement}
  201. */
  202. this.wave = null;
  203. /**
  204. * The wave canvas rendering context
  205. *
  206. * @type {CanvasRenderingContext2D}
  207. */
  208. this.waveCtx = null;
  209. /**
  210. * The (optional) progress wave node
  211. *
  212. * @type {HTMLCanvasElement}
  213. */
  214. this.progress = null;
  215. /**
  216. * The (optional) progress wave canvas rendering context
  217. *
  218. * @type {CanvasRenderingContext2D}
  219. */
  220. this.progressCtx = null;
  221. /**
  222. * Start of the area the canvas should render, between 0 and 1
  223. *
  224. * @type {number}
  225. */
  226. this.start = 0;
  227. /**
  228. * End of the area the canvas should render, between 0 and 1
  229. *
  230. * @type {number}
  231. */
  232. this.end = 1;
  233. /**
  234. * Unique identifier for this entry
  235. *
  236. * @type {string}
  237. */
  238. this.id = (0, _getId.default)(typeof this.constructor.name !== 'undefined' ? this.constructor.name.toLowerCase() + '_' : 'canvasentry_');
  239. /**
  240. * Canvas 2d context attributes
  241. *
  242. * @type {object}
  243. */
  244. this.canvasContextAttributes = {};
  245. }
  246. /**
  247. * Store the wave canvas element and create the 2D rendering context
  248. *
  249. * @param {HTMLCanvasElement} element The wave `canvas` element.
  250. */
  251. _createClass(CanvasEntry, [{
  252. key: "initWave",
  253. value: function initWave(element) {
  254. this.wave = element;
  255. this.waveCtx = this.wave.getContext('2d', this.canvasContextAttributes);
  256. }
  257. /**
  258. * Store the progress wave canvas element and create the 2D rendering
  259. * context
  260. *
  261. * @param {HTMLCanvasElement} element The progress wave `canvas` element.
  262. */
  263. }, {
  264. key: "initProgress",
  265. value: function initProgress(element) {
  266. this.progress = element;
  267. this.progressCtx = this.progress.getContext('2d', this.canvasContextAttributes);
  268. }
  269. /**
  270. * Update the dimensions
  271. *
  272. * @param {number} elementWidth Width of the entry
  273. * @param {number} totalWidth Total width of the multi canvas renderer
  274. * @param {number} width The new width of the element
  275. * @param {number} height The new height of the element
  276. */
  277. }, {
  278. key: "updateDimensions",
  279. value: function updateDimensions(elementWidth, totalWidth, width, height) {
  280. // where the canvas starts and ends in the waveform, represented as a
  281. // decimal between 0 and 1
  282. this.start = this.wave.offsetLeft / totalWidth || 0;
  283. this.end = this.start + elementWidth / totalWidth; // set wave canvas dimensions
  284. this.wave.width = width;
  285. this.wave.height = height;
  286. var elementSize = {
  287. width: elementWidth + 'px'
  288. };
  289. (0, _style.default)(this.wave, elementSize);
  290. if (this.hasProgressCanvas) {
  291. // set progress canvas dimensions
  292. this.progress.width = width;
  293. this.progress.height = height;
  294. (0, _style.default)(this.progress, elementSize);
  295. }
  296. }
  297. /**
  298. * Clear the wave and progress rendering contexts
  299. */
  300. }, {
  301. key: "clearWave",
  302. value: function clearWave() {
  303. // wave
  304. this.waveCtx.clearRect(0, 0, this.waveCtx.canvas.width, this.waveCtx.canvas.height); // progress
  305. if (this.hasProgressCanvas) {
  306. this.progressCtx.clearRect(0, 0, this.progressCtx.canvas.width, this.progressCtx.canvas.height);
  307. }
  308. }
  309. /**
  310. * Set the fill styles for wave and progress
  311. *
  312. * @param {string} waveColor Fill color for the wave canvas
  313. * @param {?string} progressColor Fill color for the progress canvas
  314. */
  315. }, {
  316. key: "setFillStyles",
  317. value: function setFillStyles(waveColor, progressColor) {
  318. this.waveCtx.fillStyle = waveColor;
  319. if (this.hasProgressCanvas) {
  320. this.progressCtx.fillStyle = progressColor;
  321. }
  322. }
  323. /**
  324. * Draw a rectangle for wave and progress
  325. *
  326. * @param {number} x X start position
  327. * @param {number} y Y start position
  328. * @param {number} width Width of the rectangle
  329. * @param {number} height Height of the rectangle
  330. * @param {number} radius Radius of the rectangle
  331. */
  332. }, {
  333. key: "fillRects",
  334. value: function fillRects(x, y, width, height, radius) {
  335. this.fillRectToContext(this.waveCtx, x, y, width, height, radius);
  336. if (this.hasProgressCanvas) {
  337. this.fillRectToContext(this.progressCtx, x, y, width, height, radius);
  338. }
  339. }
  340. /**
  341. * Draw the actual rectangle on a `canvas` element
  342. *
  343. * @param {CanvasRenderingContext2D} ctx Rendering context of target canvas
  344. * @param {number} x X start position
  345. * @param {number} y Y start position
  346. * @param {number} width Width of the rectangle
  347. * @param {number} height Height of the rectangle
  348. * @param {number} radius Radius of the rectangle
  349. */
  350. }, {
  351. key: "fillRectToContext",
  352. value: function fillRectToContext(ctx, x, y, width, height, radius) {
  353. if (!ctx) {
  354. return;
  355. }
  356. if (radius) {
  357. this.drawRoundedRect(ctx, x, y, width, height, radius);
  358. } else {
  359. ctx.fillRect(x, y, width, height);
  360. }
  361. }
  362. /**
  363. * Draw a rounded rectangle on Canvas
  364. *
  365. * @param {CanvasRenderingContext2D} ctx Canvas context
  366. * @param {number} x X-position of the rectangle
  367. * @param {number} y Y-position of the rectangle
  368. * @param {number} width Width of the rectangle
  369. * @param {number} height Height of the rectangle
  370. * @param {number} radius Radius of the rectangle
  371. *
  372. * @return {void}
  373. * @example drawRoundedRect(ctx, 50, 50, 5, 10, 3)
  374. */
  375. }, {
  376. key: "drawRoundedRect",
  377. value: function drawRoundedRect(ctx, x, y, width, height, radius) {
  378. if (height === 0) {
  379. return;
  380. } // peaks are float values from -1 to 1. Use absolute height values in
  381. // order to correctly calculate rounded rectangle coordinates
  382. if (height < 0) {
  383. height *= -1;
  384. y -= height;
  385. }
  386. ctx.beginPath();
  387. ctx.moveTo(x + radius, y);
  388. ctx.lineTo(x + width - radius, y);
  389. ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
  390. ctx.lineTo(x + width, y + height - radius);
  391. ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
  392. ctx.lineTo(x + radius, y + height);
  393. ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
  394. ctx.lineTo(x, y + radius);
  395. ctx.quadraticCurveTo(x, y, x + radius, y);
  396. ctx.closePath();
  397. ctx.fill();
  398. }
  399. /**
  400. * Render the actual wave and progress lines
  401. *
  402. * @param {number[]} peaks Array with peaks data
  403. * @param {number} absmax Maximum peak value (absolute)
  404. * @param {number} halfH Half the height of the waveform
  405. * @param {number} offsetY Offset to the top
  406. * @param {number} start The x-offset of the beginning of the area that
  407. * should be rendered
  408. * @param {number} end The x-offset of the end of the area that
  409. * should be rendered
  410. */
  411. }, {
  412. key: "drawLines",
  413. value: function drawLines(peaks, absmax, halfH, offsetY, start, end) {
  414. this.drawLineToContext(this.waveCtx, peaks, absmax, halfH, offsetY, start, end);
  415. if (this.hasProgressCanvas) {
  416. this.drawLineToContext(this.progressCtx, peaks, absmax, halfH, offsetY, start, end);
  417. }
  418. }
  419. /**
  420. * Render the actual waveform line on a `canvas` element
  421. *
  422. * @param {CanvasRenderingContext2D} ctx Rendering context of target canvas
  423. * @param {number[]} peaks Array with peaks data
  424. * @param {number} absmax Maximum peak value (absolute)
  425. * @param {number} halfH Half the height of the waveform
  426. * @param {number} offsetY Offset to the top
  427. * @param {number} start The x-offset of the beginning of the area that
  428. * should be rendered
  429. * @param {number} end The x-offset of the end of the area that
  430. * should be rendered
  431. */
  432. }, {
  433. key: "drawLineToContext",
  434. value: function drawLineToContext(ctx, peaks, absmax, halfH, offsetY, start, end) {
  435. if (!ctx) {
  436. return;
  437. }
  438. var length = peaks.length / 2;
  439. var first = Math.round(length * this.start); // use one more peak value to make sure we join peaks at ends -- unless,
  440. // of course, this is the last canvas
  441. var last = Math.round(length * this.end) + 1;
  442. var canvasStart = first;
  443. var canvasEnd = last;
  444. var scale = this.wave.width / (canvasEnd - canvasStart - 1); // optimization
  445. var halfOffset = halfH + offsetY;
  446. var absmaxHalf = absmax / halfH;
  447. ctx.beginPath();
  448. ctx.moveTo((canvasStart - first) * scale, halfOffset);
  449. ctx.lineTo((canvasStart - first) * scale, halfOffset - Math.round((peaks[2 * canvasStart] || 0) / absmaxHalf));
  450. var i, peak, h;
  451. for (i = canvasStart; i < canvasEnd; i++) {
  452. peak = peaks[2 * i] || 0;
  453. h = Math.round(peak / absmaxHalf);
  454. ctx.lineTo((i - first) * scale + this.halfPixel, halfOffset - h);
  455. } // draw the bottom edge going backwards, to make a single
  456. // closed hull to fill
  457. var j = canvasEnd - 1;
  458. for (j; j >= canvasStart; j--) {
  459. peak = peaks[2 * j + 1] || 0;
  460. h = Math.round(peak / absmaxHalf);
  461. ctx.lineTo((j - first) * scale + this.halfPixel, halfOffset - h);
  462. }
  463. ctx.lineTo((canvasStart - first) * scale, halfOffset - Math.round((peaks[2 * canvasStart + 1] || 0) / absmaxHalf));
  464. ctx.closePath();
  465. ctx.fill();
  466. }
  467. /**
  468. * Destroys this entry
  469. */
  470. }, {
  471. key: "destroy",
  472. value: function destroy() {
  473. this.waveCtx = null;
  474. this.wave = null;
  475. this.progressCtx = null;
  476. this.progress = null;
  477. }
  478. /**
  479. * Return image data of the wave `canvas` element
  480. *
  481. * When using a `type` of `'blob'`, this will return a `Promise` that
  482. * resolves with a `Blob` instance.
  483. *
  484. * @param {string} format='image/png' An optional value of a format type.
  485. * @param {number} quality=0.92 An optional value between 0 and 1.
  486. * @param {string} type='dataURL' Either 'dataURL' or 'blob'.
  487. * @return {string|Promise} When using the default `'dataURL'` `type` this
  488. * returns a data URL. When using the `'blob'` `type` this returns a
  489. * `Promise` that resolves with a `Blob` instance.
  490. */
  491. }, {
  492. key: "getImage",
  493. value: function getImage(format, quality, type) {
  494. var _this = this;
  495. if (type === 'blob') {
  496. return new Promise(function (resolve) {
  497. _this.wave.toBlob(resolve, format, quality);
  498. });
  499. } else if (type === 'dataURL') {
  500. return this.wave.toDataURL(format, quality);
  501. }
  502. }
  503. }]);
  504. return CanvasEntry;
  505. }();
  506. exports.default = CanvasEntry;
  507. module.exports = exports.default;
  508. /***/ }),
  509. /***/ "./src/drawer.js":
  510. /*!***********************!*\
  511. !*** ./src/drawer.js ***!
  512. \***********************/
  513. /*! no static exports found */
  514. /***/ (function(module, exports, __webpack_require__) {
  515. "use strict";
  516. Object.defineProperty(exports, "__esModule", {
  517. value: true
  518. });
  519. exports.default = void 0;
  520. var util = _interopRequireWildcard(__webpack_require__(/*! ./util */ "./src/util/index.js"));
  521. function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; }
  522. function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
  523. function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
  524. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  525. function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
  526. function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
  527. function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
  528. function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
  529. function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
  530. function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
  531. function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
  532. function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
  533. function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
  534. /**
  535. * Parent class for renderers
  536. *
  537. * @extends {Observer}
  538. */
  539. var Drawer = /*#__PURE__*/function (_util$Observer) {
  540. _inherits(Drawer, _util$Observer);
  541. var _super = _createSuper(Drawer);
  542. /**
  543. * @param {HTMLElement} container The container node of the wavesurfer instance
  544. * @param {WavesurferParams} params The wavesurfer initialisation options
  545. */
  546. function Drawer(container, params) {
  547. var _this;
  548. _classCallCheck(this, Drawer);
  549. _this = _super.call(this);
  550. _this.container = container;
  551. /**
  552. * @type {WavesurferParams}
  553. */
  554. _this.params = params;
  555. /**
  556. * The width of the renderer
  557. * @type {number}
  558. */
  559. _this.width = 0;
  560. /**
  561. * The height of the renderer
  562. * @type {number}
  563. */
  564. _this.height = params.height * _this.params.pixelRatio;
  565. _this.lastPos = 0;
  566. /**
  567. * The `<wave>` element which is added to the container
  568. * @type {HTMLElement}
  569. */
  570. _this.wrapper = null;
  571. return _this;
  572. }
  573. /**
  574. * Alias of `util.style`
  575. *
  576. * @param {HTMLElement} el The element that the styles will be applied to
  577. * @param {Object} styles The map of propName: attribute, both are used as-is
  578. * @return {HTMLElement} el
  579. */
  580. _createClass(Drawer, [{
  581. key: "style",
  582. value: function style(el, styles) {
  583. return util.style(el, styles);
  584. }
  585. /**
  586. * Create the wrapper `<wave>` element, style it and set up the events for
  587. * interaction
  588. */
  589. }, {
  590. key: "createWrapper",
  591. value: function createWrapper() {
  592. this.wrapper = this.container.appendChild(document.createElement('wave'));
  593. this.style(this.wrapper, {
  594. display: 'block',
  595. position: 'relative',
  596. userSelect: 'none',
  597. webkitUserSelect: 'none',
  598. height: this.params.height + 'px'
  599. });
  600. if (this.params.fillParent || this.params.scrollParent) {
  601. this.style(this.wrapper, {
  602. width: '100%',
  603. overflowX: this.params.hideScrollbar ? 'hidden' : 'auto',
  604. overflowY: 'hidden'
  605. });
  606. }
  607. this.setupWrapperEvents();
  608. }
  609. /**
  610. * Handle click event
  611. *
  612. * @param {Event} e Click event
  613. * @param {?boolean} noPrevent Set to true to not call `e.preventDefault()`
  614. * @return {number} Playback position from 0 to 1
  615. */
  616. }, {
  617. key: "handleEvent",
  618. value: function handleEvent(e, noPrevent) {
  619. !noPrevent && e.preventDefault();
  620. var clientX = e.targetTouches ? e.targetTouches[0].clientX : e.clientX;
  621. var bbox = this.wrapper.getBoundingClientRect();
  622. var nominalWidth = this.width;
  623. var parentWidth = this.getWidth();
  624. var progress;
  625. if (!this.params.fillParent && nominalWidth < parentWidth) {
  626. progress = (this.params.rtl ? bbox.right - clientX : clientX - bbox.left) * (this.params.pixelRatio / nominalWidth) || 0;
  627. } else {
  628. progress = ((this.params.rtl ? bbox.right - clientX : clientX - bbox.left) + this.wrapper.scrollLeft) / this.wrapper.scrollWidth || 0;
  629. }
  630. return util.clamp(progress, 0, 1);
  631. }
  632. }, {
  633. key: "setupWrapperEvents",
  634. value: function setupWrapperEvents() {
  635. var _this2 = this;
  636. this.wrapper.addEventListener('click', function (e) {
  637. var scrollbarHeight = _this2.wrapper.offsetHeight - _this2.wrapper.clientHeight;
  638. if (scrollbarHeight !== 0) {
  639. // scrollbar is visible. Check if click was on it
  640. var bbox = _this2.wrapper.getBoundingClientRect();
  641. if (e.clientY >= bbox.bottom - scrollbarHeight) {
  642. // ignore mousedown as it was on the scrollbar
  643. return;
  644. }
  645. }
  646. if (_this2.params.interact) {
  647. _this2.fireEvent('click', e, _this2.handleEvent(e));
  648. }
  649. });
  650. this.wrapper.addEventListener('dblclick', function (e) {
  651. if (_this2.params.interact) {
  652. _this2.fireEvent('dblclick', e, _this2.handleEvent(e));
  653. }
  654. });
  655. this.wrapper.addEventListener('scroll', function (e) {
  656. return _this2.fireEvent('scroll', e);
  657. });
  658. }
  659. /**
  660. * Draw peaks on the canvas
  661. *
  662. * @param {number[]|Number.<Array[]>} peaks Can also be an array of arrays
  663. * for split channel rendering
  664. * @param {number} length The width of the area that should be drawn
  665. * @param {number} start The x-offset of the beginning of the area that
  666. * should be rendered
  667. * @param {number} end The x-offset of the end of the area that should be
  668. * rendered
  669. */
  670. }, {
  671. key: "drawPeaks",
  672. value: function drawPeaks(peaks, length, start, end) {
  673. if (!this.setWidth(length)) {
  674. this.clearWave();
  675. }
  676. this.params.barWidth ? this.drawBars(peaks, 0, start, end) : this.drawWave(peaks, 0, start, end);
  677. }
  678. /**
  679. * Scroll to the beginning
  680. */
  681. }, {
  682. key: "resetScroll",
  683. value: function resetScroll() {
  684. if (this.wrapper !== null) {
  685. this.wrapper.scrollLeft = 0;
  686. }
  687. }
  688. /**
  689. * Recenter the view-port at a certain percent of the waveform
  690. *
  691. * @param {number} percent Value from 0 to 1 on the waveform
  692. */
  693. }, {
  694. key: "recenter",
  695. value: function recenter(percent) {
  696. var position = this.wrapper.scrollWidth * percent;
  697. this.recenterOnPosition(position, true);
  698. }
  699. /**
  700. * Recenter the view-port on a position, either scroll there immediately or
  701. * in steps of 5 pixels
  702. *
  703. * @param {number} position X-offset in pixels
  704. * @param {boolean} immediate Set to true to immediately scroll somewhere
  705. */
  706. }, {
  707. key: "recenterOnPosition",
  708. value: function recenterOnPosition(position, immediate) {
  709. var scrollLeft = this.wrapper.scrollLeft;
  710. var half = ~~(this.wrapper.clientWidth / 2);
  711. var maxScroll = this.wrapper.scrollWidth - this.wrapper.clientWidth;
  712. var target = position - half;
  713. var offset = target - scrollLeft;
  714. if (maxScroll == 0) {
  715. // no need to continue if scrollbar is not there
  716. return;
  717. } // if the cursor is currently visible...
  718. if (!immediate && -half <= offset && offset < half) {
  719. // set rate at which waveform is centered
  720. var rate = this.params.autoCenterRate; // make rate depend on width of view and length of waveform
  721. rate /= half;
  722. rate *= maxScroll;
  723. offset = Math.max(-rate, Math.min(rate, offset));
  724. target = scrollLeft + offset;
  725. } // limit target to valid range (0 to maxScroll)
  726. target = Math.max(0, Math.min(maxScroll, target)); // no use attempting to scroll if we're not moving
  727. if (target != scrollLeft) {
  728. this.wrapper.scrollLeft = target;
  729. }
  730. }
  731. /**
  732. * Get the current scroll position in pixels
  733. *
  734. * @return {number} Horizontal scroll position in pixels
  735. */
  736. }, {
  737. key: "getScrollX",
  738. value: function getScrollX() {
  739. var x = 0;
  740. if (this.wrapper) {
  741. var pixelRatio = this.params.pixelRatio;
  742. x = Math.round(this.wrapper.scrollLeft * pixelRatio); // In cases of elastic scroll (safari with mouse wheel) you can
  743. // scroll beyond the limits of the container
  744. // Calculate and floor the scrollable extent to make sure an out
  745. // of bounds value is not returned
  746. // Ticket #1312
  747. if (this.params.scrollParent) {
  748. var maxScroll = ~~(this.wrapper.scrollWidth * pixelRatio - this.getWidth());
  749. x = Math.min(maxScroll, Math.max(0, x));
  750. }
  751. }
  752. return x;
  753. }
  754. /**
  755. * Get the width of the container
  756. *
  757. * @return {number} The width of the container
  758. */
  759. }, {
  760. key: "getWidth",
  761. value: function getWidth() {
  762. return Math.round(this.container.clientWidth * this.params.pixelRatio);
  763. }
  764. /**
  765. * Set the width of the container
  766. *
  767. * @param {number} width The new width of the container
  768. * @return {boolean} Whether the width of the container was updated or not
  769. */
  770. }, {
  771. key: "setWidth",
  772. value: function setWidth(width) {
  773. if (this.width == width) {
  774. return false;
  775. }
  776. this.width = width;
  777. if (this.params.fillParent || this.params.scrollParent) {
  778. this.style(this.wrapper, {
  779. width: ''
  780. });
  781. } else {
  782. this.style(this.wrapper, {
  783. width: ~~(this.width / this.params.pixelRatio) + 'px'
  784. });
  785. }
  786. this.updateSize();
  787. return true;
  788. }
  789. /**
  790. * Set the height of the container
  791. *
  792. * @param {number} height The new height of the container.
  793. * @return {boolean} Whether the height of the container was updated or not
  794. */
  795. }, {
  796. key: "setHeight",
  797. value: function setHeight(height) {
  798. if (height == this.height) {
  799. return false;
  800. }
  801. this.height = height;
  802. this.style(this.wrapper, {
  803. height: ~~(this.height / this.params.pixelRatio) + 'px'
  804. });
  805. this.updateSize();
  806. return true;
  807. }
  808. /**
  809. * Called by wavesurfer when progress should be rendered
  810. *
  811. * @param {number} progress From 0 to 1
  812. */
  813. }, {
  814. key: "progress",
  815. value: function progress(_progress) {
  816. var minPxDelta = 1 / this.params.pixelRatio;
  817. var pos = Math.round(_progress * this.width) * minPxDelta;
  818. if (pos < this.lastPos || pos - this.lastPos >= minPxDelta) {
  819. this.lastPos = pos;
  820. if (this.params.scrollParent && this.params.autoCenter) {
  821. var newPos = ~~(this.wrapper.scrollWidth * _progress);
  822. this.recenterOnPosition(newPos, this.params.autoCenterImmediately);
  823. }
  824. this.updateProgress(pos);
  825. }
  826. }
  827. /**
  828. * This is called when wavesurfer is destroyed
  829. */
  830. }, {
  831. key: "destroy",
  832. value: function destroy() {
  833. this.unAll();
  834. if (this.wrapper) {
  835. if (this.wrapper.parentNode == this.container) {
  836. this.container.removeChild(this.wrapper);
  837. }
  838. this.wrapper = null;
  839. }
  840. }
  841. /* Renderer-specific methods */
  842. /**
  843. * Called after cursor related params have changed.
  844. *
  845. * @abstract
  846. */
  847. }, {
  848. key: "updateCursor",
  849. value: function updateCursor() {}
  850. /**
  851. * Called when the size of the container changes so the renderer can adjust
  852. *
  853. * @abstract
  854. */
  855. }, {
  856. key: "updateSize",
  857. value: function updateSize() {}
  858. /**
  859. * Draw a waveform with bars
  860. *
  861. * @abstract
  862. * @param {number[]|Number.<Array[]>} peaks Can also be an array of arrays for split channel
  863. * rendering
  864. * @param {number} channelIndex The index of the current channel. Normally
  865. * should be 0
  866. * @param {number} start The x-offset of the beginning of the area that
  867. * should be rendered
  868. * @param {number} end The x-offset of the end of the area that should be
  869. * rendered
  870. */
  871. }, {
  872. key: "drawBars",
  873. value: function drawBars(peaks, channelIndex, start, end) {}
  874. /**
  875. * Draw a waveform
  876. *
  877. * @abstract
  878. * @param {number[]|Number.<Array[]>} peaks Can also be an array of arrays for split channel
  879. * rendering
  880. * @param {number} channelIndex The index of the current channel. Normally
  881. * should be 0
  882. * @param {number} start The x-offset of the beginning of the area that
  883. * should be rendered
  884. * @param {number} end The x-offset of the end of the area that should be
  885. * rendered
  886. */
  887. }, {
  888. key: "drawWave",
  889. value: function drawWave(peaks, channelIndex, start, end) {}
  890. /**
  891. * Clear the waveform
  892. *
  893. * @abstract
  894. */
  895. }, {
  896. key: "clearWave",
  897. value: function clearWave() {}
  898. /**
  899. * Render the new progress
  900. *
  901. * @abstract
  902. * @param {number} position X-Offset of progress position in pixels
  903. */
  904. }, {
  905. key: "updateProgress",
  906. value: function updateProgress(position) {}
  907. }]);
  908. return Drawer;
  909. }(util.Observer);
  910. exports.default = Drawer;
  911. module.exports = exports.default;
  912. /***/ }),
  913. /***/ "./src/drawer.multicanvas.js":
  914. /*!***********************************!*\
  915. !*** ./src/drawer.multicanvas.js ***!
  916. \***********************************/
  917. /*! no static exports found */
  918. /***/ (function(module, exports, __webpack_require__) {
  919. "use strict";
  920. Object.defineProperty(exports, "__esModule", {
  921. value: true
  922. });
  923. exports.default = void 0;
  924. var _drawer = _interopRequireDefault(__webpack_require__(/*! ./drawer */ "./src/drawer.js"));
  925. var util = _interopRequireWildcard(__webpack_require__(/*! ./util */ "./src/util/index.js"));
  926. var _drawer2 = _interopRequireDefault(__webpack_require__(/*! ./drawer.canvasentry */ "./src/drawer.canvasentry.js"));
  927. function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; }
  928. function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
  929. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  930. function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
  931. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  932. function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
  933. function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
  934. function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
  935. function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
  936. function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
  937. function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
  938. function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
  939. function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
  940. function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
  941. /**
  942. * MultiCanvas renderer for wavesurfer. Is currently the default and sole
  943. * builtin renderer.
  944. *
  945. * A `MultiCanvas` consists of one or more `CanvasEntry` instances, depending
  946. * on the zoom level.
  947. */
  948. var MultiCanvas = /*#__PURE__*/function (_Drawer) {
  949. _inherits(MultiCanvas, _Drawer);
  950. var _super = _createSuper(MultiCanvas);
  951. /**
  952. * @param {HTMLElement} container The container node of the wavesurfer instance
  953. * @param {WavesurferParams} params The wavesurfer initialisation options
  954. */
  955. function MultiCanvas(container, params) {
  956. var _this;
  957. _classCallCheck(this, MultiCanvas);
  958. _this = _super.call(this, container, params);
  959. /**
  960. * @type {number}
  961. */
  962. _this.maxCanvasWidth = params.maxCanvasWidth;
  963. /**
  964. * @type {number}
  965. */
  966. _this.maxCanvasElementWidth = Math.round(params.maxCanvasWidth / params.pixelRatio);
  967. /**
  968. * Whether or not the progress wave is rendered. If the `waveColor`
  969. * and `progressColor` are the same color it is not.
  970. *
  971. * @type {boolean}
  972. */
  973. _this.hasProgressCanvas = params.waveColor != params.progressColor;
  974. /**
  975. * @type {number}
  976. */
  977. _this.halfPixel = 0.5 / params.pixelRatio;
  978. /**
  979. * List of `CanvasEntry` instances.
  980. *
  981. * @type {Array}
  982. */
  983. _this.canvases = [];
  984. /**
  985. * @type {HTMLElement}
  986. */
  987. _this.progressWave = null;
  988. /**
  989. * Class used to generate entries.
  990. *
  991. * @type {function}
  992. */
  993. _this.EntryClass = _drawer2.default;
  994. /**
  995. * Canvas 2d context attributes.
  996. *
  997. * @type {object}
  998. */
  999. _this.canvasContextAttributes = params.drawingContextAttributes;
  1000. /**
  1001. * Overlap added between entries to prevent vertical white stripes
  1002. * between `canvas` elements.
  1003. *
  1004. * @type {number}
  1005. */
  1006. _this.overlap = 2 * Math.ceil(params.pixelRatio / 2);
  1007. /**
  1008. * The radius of the wave bars. Makes bars rounded
  1009. *
  1010. * @type {number}
  1011. */
  1012. _this.barRadius = params.barRadius || 0;
  1013. return _this;
  1014. }
  1015. /**
  1016. * Initialize the drawer
  1017. */
  1018. _createClass(MultiCanvas, [{
  1019. key: "init",
  1020. value: function init() {
  1021. this.createWrapper();
  1022. this.createElements();
  1023. }
  1024. /**
  1025. * Create the canvas elements and style them
  1026. *
  1027. */
  1028. }, {
  1029. key: "createElements",
  1030. value: function createElements() {
  1031. this.progressWave = this.wrapper.appendChild(this.style(document.createElement('wave'), {
  1032. position: 'absolute',
  1033. zIndex: 3,
  1034. left: 0,
  1035. top: 0,
  1036. bottom: 0,
  1037. overflow: 'hidden',
  1038. width: '0',
  1039. display: 'none',
  1040. boxSizing: 'border-box',
  1041. borderRightStyle: 'solid',
  1042. pointerEvents: 'none'
  1043. }));
  1044. this.addCanvas();
  1045. this.updateCursor();
  1046. }
  1047. /**
  1048. * Update cursor style
  1049. */
  1050. }, {
  1051. key: "updateCursor",
  1052. value: function updateCursor() {
  1053. this.style(this.progressWave, {
  1054. borderRightWidth: this.params.cursorWidth + 'px',
  1055. borderRightColor: this.params.cursorColor
  1056. });
  1057. }
  1058. /**
  1059. * Adjust to the updated size by adding or removing canvases
  1060. */
  1061. }, {
  1062. key: "updateSize",
  1063. value: function updateSize() {
  1064. var _this2 = this;
  1065. var totalWidth = Math.round(this.width / this.params.pixelRatio);
  1066. var requiredCanvases = Math.ceil(totalWidth / (this.maxCanvasElementWidth + this.overlap)); // add required canvases
  1067. while (this.canvases.length < requiredCanvases) {
  1068. this.addCanvas();
  1069. } // remove older existing canvases, if any
  1070. while (this.canvases.length > requiredCanvases) {
  1071. this.removeCanvas();
  1072. }
  1073. var canvasWidth = this.maxCanvasWidth + this.overlap;
  1074. var lastCanvas = this.canvases.length - 1;
  1075. this.canvases.forEach(function (entry, i) {
  1076. if (i == lastCanvas) {
  1077. canvasWidth = _this2.width - _this2.maxCanvasWidth * lastCanvas;
  1078. }
  1079. _this2.updateDimensions(entry, canvasWidth, _this2.height);
  1080. entry.clearWave();
  1081. });
  1082. }
  1083. /**
  1084. * Add a canvas to the canvas list
  1085. *
  1086. */
  1087. }, {
  1088. key: "addCanvas",
  1089. value: function addCanvas() {
  1090. var entry = new this.EntryClass();
  1091. entry.canvasContextAttributes = this.canvasContextAttributes;
  1092. entry.hasProgressCanvas = this.hasProgressCanvas;
  1093. entry.halfPixel = this.halfPixel;
  1094. var leftOffset = this.maxCanvasElementWidth * this.canvases.length; // wave
  1095. entry.initWave(this.wrapper.appendChild(this.style(document.createElement('canvas'), {
  1096. position: 'absolute',
  1097. zIndex: 2,
  1098. left: leftOffset + 'px',
  1099. top: 0,
  1100. bottom: 0,
  1101. height: '100%',
  1102. pointerEvents: 'none'
  1103. }))); // progress
  1104. if (this.hasProgressCanvas) {
  1105. entry.initProgress(this.progressWave.appendChild(this.style(document.createElement('canvas'), {
  1106. position: 'absolute',
  1107. left: leftOffset + 'px',
  1108. top: 0,
  1109. bottom: 0,
  1110. height: '100%'
  1111. })));
  1112. }
  1113. this.canvases.push(entry);
  1114. }
  1115. /**
  1116. * Pop single canvas from the list
  1117. *
  1118. */
  1119. }, {
  1120. key: "removeCanvas",
  1121. value: function removeCanvas() {
  1122. var lastEntry = this.canvases[this.canvases.length - 1]; // wave
  1123. lastEntry.wave.parentElement.removeChild(lastEntry.wave); // progress
  1124. if (this.hasProgressCanvas) {
  1125. lastEntry.progress.parentElement.removeChild(lastEntry.progress);
  1126. } // cleanup
  1127. if (lastEntry) {
  1128. lastEntry.destroy();
  1129. lastEntry = null;
  1130. }
  1131. this.canvases.pop();
  1132. }
  1133. /**
  1134. * Update the dimensions of a canvas element
  1135. *
  1136. * @param {CanvasEntry} entry Target entry
  1137. * @param {number} width The new width of the element
  1138. * @param {number} height The new height of the element
  1139. */
  1140. }, {
  1141. key: "updateDimensions",
  1142. value: function updateDimensions(entry, width, height) {
  1143. var elementWidth = Math.round(width / this.params.pixelRatio);
  1144. var totalWidth = Math.round(this.width / this.params.pixelRatio); // update canvas dimensions
  1145. entry.updateDimensions(elementWidth, totalWidth, width, height); // style element
  1146. this.style(this.progressWave, {
  1147. display: 'block'
  1148. });
  1149. }
  1150. /**
  1151. * Clear the whole multi-canvas
  1152. */
  1153. }, {
  1154. key: "clearWave",
  1155. value: function clearWave() {
  1156. var _this3 = this;
  1157. util.frame(function () {
  1158. _this3.canvases.forEach(function (entry) {
  1159. return entry.clearWave();
  1160. });
  1161. })();
  1162. }
  1163. /**
  1164. * Draw a waveform with bars
  1165. *
  1166. * @param {number[]|Number.<Array[]>} peaks Can also be an array of arrays
  1167. * for split channel rendering
  1168. * @param {number} channelIndex The index of the current channel. Normally
  1169. * should be 0. Must be an integer.
  1170. * @param {number} start The x-offset of the beginning of the area that
  1171. * should be rendered
  1172. * @param {number} end The x-offset of the end of the area that should be
  1173. * rendered
  1174. * @returns {void}
  1175. */
  1176. }, {
  1177. key: "drawBars",
  1178. value: function drawBars(peaks, channelIndex, start, end) {
  1179. var _this4 = this;
  1180. return this.prepareDraw(peaks, channelIndex, start, end, function (_ref) {
  1181. var absmax = _ref.absmax,
  1182. hasMinVals = _ref.hasMinVals,
  1183. height = _ref.height,
  1184. offsetY = _ref.offsetY,
  1185. halfH = _ref.halfH,
  1186. peaks = _ref.peaks;
  1187. // if drawBars was called within ws.empty we don't pass a start and
  1188. // don't want anything to happen
  1189. if (start === undefined) {
  1190. return;
  1191. } // Skip every other value if there are negatives.
  1192. var peakIndexScale = hasMinVals ? 2 : 1;
  1193. var length = peaks.length / peakIndexScale;
  1194. var bar = _this4.params.barWidth * _this4.params.pixelRatio;
  1195. var gap = _this4.params.barGap === null ? Math.max(_this4.params.pixelRatio, ~~(bar / 2)) : Math.max(_this4.params.pixelRatio, _this4.params.barGap * _this4.params.pixelRatio);
  1196. var step = bar + gap;
  1197. var scale = length / _this4.width;
  1198. var first = start;
  1199. var last = end;
  1200. var i = first;
  1201. for (i; i < last; i += step) {
  1202. var peak = peaks[Math.floor(i * scale * peakIndexScale)] || 0;
  1203. var h = Math.round(peak / absmax * halfH);
  1204. /* in case of silences, allow the user to specify that we
  1205. * always draw *something* (normally a 1px high bar) */
  1206. if (h == 0 && _this4.params.barMinHeight) h = _this4.params.barMinHeight;
  1207. _this4.fillRect(i + _this4.halfPixel, halfH - h + offsetY, bar + _this4.halfPixel, h * 2, _this4.barRadius);
  1208. }
  1209. });
  1210. }
  1211. /**
  1212. * Draw a waveform
  1213. *
  1214. * @param {number[]|Number.<Array[]>} peaks Can also be an array of arrays
  1215. * for split channel rendering
  1216. * @param {number} channelIndex The index of the current channel. Normally
  1217. * should be 0
  1218. * @param {number?} start The x-offset of the beginning of the area that
  1219. * should be rendered (If this isn't set only a flat line is rendered)
  1220. * @param {number?} end The x-offset of the end of the area that should be
  1221. * rendered
  1222. * @returns {void}
  1223. */
  1224. }, {
  1225. key: "drawWave",
  1226. value: function drawWave(peaks, channelIndex, start, end) {
  1227. var _this5 = this;
  1228. return this.prepareDraw(peaks, channelIndex, start, end, function (_ref2) {
  1229. var absmax = _ref2.absmax,
  1230. hasMinVals = _ref2.hasMinVals,
  1231. height = _ref2.height,
  1232. offsetY = _ref2.offsetY,
  1233. halfH = _ref2.halfH,
  1234. peaks = _ref2.peaks,
  1235. channelIndex = _ref2.channelIndex;
  1236. if (!hasMinVals) {
  1237. var reflectedPeaks = [];
  1238. var len = peaks.length;
  1239. var i = 0;
  1240. for (i; i < len; i++) {
  1241. reflectedPeaks[2 * i] = peaks[i];
  1242. reflectedPeaks[2 * i + 1] = -peaks[i];
  1243. }
  1244. peaks = reflectedPeaks;
  1245. } // if drawWave was called within ws.empty we don't pass a start and
  1246. // end and simply want a flat line
  1247. if (start !== undefined) {
  1248. _this5.drawLine(peaks, absmax, halfH, offsetY, start, end, channelIndex);
  1249. } // always draw a median line
  1250. _this5.fillRect(0, halfH + offsetY - _this5.halfPixel, _this5.width, _this5.halfPixel, _this5.barRadius);
  1251. });
  1252. }
  1253. /**
  1254. * Tell the canvas entries to render their portion of the waveform
  1255. *
  1256. * @param {number[]} peaks Peaks data
  1257. * @param {number} absmax Maximum peak value (absolute)
  1258. * @param {number} halfH Half the height of the waveform
  1259. * @param {number} offsetY Offset to the top
  1260. * @param {number} start The x-offset of the beginning of the area that
  1261. * should be rendered
  1262. * @param {number} end The x-offset of the end of the area that
  1263. * should be rendered
  1264. * @param {channelIndex} channelIndex The channel index of the line drawn
  1265. */
  1266. }, {
  1267. key: "drawLine",
  1268. value: function drawLine(peaks, absmax, halfH, offsetY, start, end, channelIndex) {
  1269. var _this6 = this;
  1270. var _ref3 = this.params.splitChannelsOptions.channelColors[channelIndex] || {},
  1271. waveColor = _ref3.waveColor,
  1272. progressColor = _ref3.progressColor;
  1273. this.canvases.forEach(function (entry, i) {
  1274. _this6.setFillStyles(entry, waveColor, progressColor);
  1275. entry.drawLines(peaks, absmax, halfH, offsetY, start, end);
  1276. });
  1277. }
  1278. /**
  1279. * Draw a rectangle on the multi-canvas
  1280. *
  1281. * @param {number} x X-position of the rectangle
  1282. * @param {number} y Y-position of the rectangle
  1283. * @param {number} width Width of the rectangle
  1284. * @param {number} height Height of the rectangle
  1285. * @param {number} radius Radius of the rectangle
  1286. */
  1287. }, {
  1288. key: "fillRect",
  1289. value: function fillRect(x, y, width, height, radius) {
  1290. var startCanvas = Math.floor(x / this.maxCanvasWidth);
  1291. var endCanvas = Math.min(Math.ceil((x + width) / this.maxCanvasWidth) + 1, this.canvases.length);
  1292. var i = startCanvas;
  1293. for (i; i < endCanvas; i++) {
  1294. var entry = this.canvases[i];
  1295. var leftOffset = i * this.maxCanvasWidth;
  1296. var intersection = {
  1297. x1: Math.max(x, i * this.maxCanvasWidth),
  1298. y1: y,
  1299. x2: Math.min(x + width, i * this.maxCanvasWidth + entry.wave.width),
  1300. y2: y + height
  1301. };
  1302. if (intersection.x1 < intersection.x2) {
  1303. this.setFillStyles(entry);
  1304. entry.fillRects(intersection.x1 - leftOffset, intersection.y1, intersection.x2 - intersection.x1, intersection.y2 - intersection.y1, radius);
  1305. }
  1306. }
  1307. }
  1308. /**
  1309. * Returns whether to hide the channel from being drawn based on params.
  1310. *
  1311. * @param {number} channelIndex The index of the current channel.
  1312. * @returns {bool} True to hide the channel, false to draw.
  1313. */
  1314. }, {
  1315. key: "hideChannel",
  1316. value: function hideChannel(channelIndex) {
  1317. return this.params.splitChannels && this.params.splitChannelsOptions.filterChannels.includes(channelIndex);
  1318. }
  1319. /**
  1320. * Performs preparation tasks and calculations which are shared by `drawBars`
  1321. * and `drawWave`
  1322. *
  1323. * @param {number[]|Number.<Array[]>} peaks Can also be an array of arrays for
  1324. * split channel rendering
  1325. * @param {number} channelIndex The index of the current channel. Normally
  1326. * should be 0
  1327. * @param {number?} start The x-offset of the beginning of the area that
  1328. * should be rendered. If this isn't set only a flat line is rendered
  1329. * @param {number?} end The x-offset of the end of the area that should be
  1330. * rendered
  1331. * @param {function} fn The render function to call, e.g. `drawWave`
  1332. * @param {number} drawIndex The index of the current channel after filtering.
  1333. * @returns {void}
  1334. */
  1335. }, {
  1336. key: "prepareDraw",
  1337. value: function prepareDraw(peaks, channelIndex, start, end, fn, drawIndex) {
  1338. var _this7 = this;
  1339. return util.frame(function () {
  1340. // Split channels and call this function with the channelIndex set
  1341. if (peaks[0] instanceof Array) {
  1342. var channels = peaks;
  1343. if (_this7.params.splitChannels) {
  1344. var filteredChannels = channels.filter(function (c, i) {
  1345. return !_this7.hideChannel(i);
  1346. });
  1347. if (!_this7.params.splitChannelsOptions.overlay) {
  1348. _this7.setHeight(Math.max(filteredChannels.length, 1) * _this7.params.height * _this7.params.pixelRatio);
  1349. }
  1350. return channels.forEach(function (channelPeaks, i) {
  1351. return _this7.prepareDraw(channelPeaks, i, start, end, fn, filteredChannels.indexOf(channelPeaks));
  1352. });
  1353. }
  1354. peaks = channels[0];
  1355. } // Return and do not draw channel peaks if hidden.
  1356. if (_this7.hideChannel(channelIndex)) {
  1357. return;
  1358. } // calculate maximum modulation value, either from the barHeight
  1359. // parameter or if normalize=true from the largest value in the peak
  1360. // set
  1361. var absmax = 1 / _this7.params.barHeight;
  1362. if (_this7.params.normalize) {
  1363. var max = util.max(peaks);
  1364. var min = util.min(peaks);
  1365. absmax = -min > max ? -min : max;
  1366. } // Bar wave draws the bottom only as a reflection of the top,
  1367. // so we don't need negative values
  1368. var hasMinVals = [].some.call(peaks, function (val) {
  1369. return val < 0;
  1370. });
  1371. var height = _this7.params.height * _this7.params.pixelRatio;
  1372. var offsetY = height * drawIndex || 0;
  1373. var halfH = height / 2;
  1374. return fn({
  1375. absmax: absmax,
  1376. hasMinVals: hasMinVals,
  1377. height: height,
  1378. offsetY: offsetY,
  1379. halfH: halfH,
  1380. peaks: peaks,
  1381. channelIndex: channelIndex
  1382. });
  1383. })();
  1384. }
  1385. /**
  1386. * Set the fill styles for a certain entry (wave and progress)
  1387. *
  1388. * @param {CanvasEntry} entry Target entry
  1389. * @param {string} waveColor Wave color to draw this entry
  1390. * @param {string} progressColor Progress color to draw this entry
  1391. */
  1392. }, {
  1393. key: "setFillStyles",
  1394. value: function setFillStyles(entry) {
  1395. var waveColor = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.params.waveColor;
  1396. var progressColor = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.params.progressColor;
  1397. entry.setFillStyles(waveColor, progressColor);
  1398. }
  1399. /**
  1400. * Return image data of the multi-canvas
  1401. *
  1402. * When using a `type` of `'blob'`, this will return a `Promise`.
  1403. *
  1404. * @param {string} format='image/png' An optional value of a format type.
  1405. * @param {number} quality=0.92 An optional value between 0 and 1.
  1406. * @param {string} type='dataURL' Either 'dataURL' or 'blob'.
  1407. * @return {string|string[]|Promise} When using the default `'dataURL'`
  1408. * `type` this returns a single data URL or an array of data URLs,
  1409. * one for each canvas. When using the `'blob'` `type` this returns a
  1410. * `Promise` that resolves with an array of `Blob` instances, one for each
  1411. * canvas.
  1412. */
  1413. }, {
  1414. key: "getImage",
  1415. value: function getImage(format, quality, type) {
  1416. if (type === 'blob') {
  1417. return Promise.all(this.canvases.map(function (entry) {
  1418. return entry.getImage(format, quality, type);
  1419. }));
  1420. } else if (type === 'dataURL') {
  1421. var images = this.canvases.map(function (entry) {
  1422. return entry.getImage(format, quality, type);
  1423. });
  1424. return images.length > 1 ? images : images[0];
  1425. }
  1426. }
  1427. /**
  1428. * Render the new progress
  1429. *
  1430. * @param {number} position X-offset of progress position in pixels
  1431. */
  1432. }, {
  1433. key: "updateProgress",
  1434. value: function updateProgress(position) {
  1435. this.style(this.progressWave, {
  1436. width: position + 'px'
  1437. });
  1438. }
  1439. }]);
  1440. return MultiCanvas;
  1441. }(_drawer.default);
  1442. exports.default = MultiCanvas;
  1443. module.exports = exports.default;
  1444. /***/ }),
  1445. /***/ "./src/mediaelement-webaudio.js":
  1446. /*!**************************************!*\
  1447. !*** ./src/mediaelement-webaudio.js ***!
  1448. \**************************************/
  1449. /*! no static exports found */
  1450. /***/ (function(module, exports, __webpack_require__) {
  1451. "use strict";
  1452. Object.defineProperty(exports, "__esModule", {
  1453. value: true
  1454. });
  1455. exports.default = void 0;
  1456. var _mediaelement = _interopRequireDefault(__webpack_require__(/*! ./mediaelement */ "./src/mediaelement.js"));
  1457. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  1458. function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
  1459. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  1460. function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
  1461. function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
  1462. function _get(target, property, receiver) { if (typeof Reflect !== "undefined" && Reflect.get) { _get = Reflect.get; } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(receiver); } return desc.value; }; } return _get(target, property, receiver || target); }
  1463. function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; }
  1464. function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
  1465. function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
  1466. function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
  1467. function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
  1468. function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
  1469. function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
  1470. function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
  1471. /**
  1472. * MediaElementWebAudio backend: load audio via an HTML5 audio tag, but playback with the WebAudio API.
  1473. * The advantage here is that the html5 <audio> tag can perform range requests on the server and not
  1474. * buffer the entire file in one request, and you still get the filtering and scripting functionality
  1475. * of the webaudio API.
  1476. * Note that in order to use range requests and prevent buffering, you must provide peak data.
  1477. *
  1478. * @since 3.2.0
  1479. */
  1480. var MediaElementWebAudio = /*#__PURE__*/function (_MediaElement) {
  1481. _inherits(MediaElementWebAudio, _MediaElement);
  1482. var _super = _createSuper(MediaElementWebAudio);
  1483. /**
  1484. * Construct the backend
  1485. *
  1486. * @param {WavesurferParams} params Wavesurfer parameters
  1487. */
  1488. function MediaElementWebAudio(params) {
  1489. var _this;
  1490. _classCallCheck(this, MediaElementWebAudio);
  1491. _this = _super.call(this, params);
  1492. /** @private */
  1493. _this.params = params;
  1494. /** @private */
  1495. _this.sourceMediaElement = null;
  1496. return _this;
  1497. }
  1498. /**
  1499. * Initialise the backend, called in `wavesurfer.createBackend()`
  1500. */
  1501. _createClass(MediaElementWebAudio, [{
  1502. key: "init",
  1503. value: function init() {
  1504. this.setPlaybackRate(this.params.audioRate);
  1505. this.createTimer();
  1506. this.createVolumeNode();
  1507. this.createScriptNode();
  1508. this.createAnalyserNode();
  1509. }
  1510. /**
  1511. * Private method called by both `load` (from url)
  1512. * and `loadElt` (existing media element) methods.
  1513. *
  1514. * @param {HTMLMediaElement} media HTML5 Audio or Video element
  1515. * @param {number[]|Number.<Array[]>} peaks Array of peak data
  1516. * @param {string} preload HTML 5 preload attribute value
  1517. * @private
  1518. */
  1519. }, {
  1520. key: "_load",
  1521. value: function _load(media, peaks, preload) {
  1522. _get(_getPrototypeOf(MediaElementWebAudio.prototype), "_load", this).call(this, media, peaks, preload);
  1523. this.createMediaElementSource(media);
  1524. }
  1525. /**
  1526. * Create MediaElementSource node
  1527. *
  1528. * @since 3.2.0
  1529. * @param {HTMLMediaElement} mediaElement HTML5 Audio to load
  1530. */
  1531. }, {
  1532. key: "createMediaElementSource",
  1533. value: function createMediaElementSource(mediaElement) {
  1534. this.sourceMediaElement = this.ac.createMediaElementSource(mediaElement);
  1535. this.sourceMediaElement.connect(this.analyser);
  1536. }
  1537. }, {
  1538. key: "play",
  1539. value: function play(start, end) {
  1540. this.resumeAudioContext();
  1541. return _get(_getPrototypeOf(MediaElementWebAudio.prototype), "play", this).call(this, start, end);
  1542. }
  1543. /**
  1544. * This is called when wavesurfer is destroyed
  1545. *
  1546. */
  1547. }, {
  1548. key: "destroy",
  1549. value: function destroy() {
  1550. _get(_getPrototypeOf(MediaElementWebAudio.prototype), "destroy", this).call(this);
  1551. this.destroyWebAudio();
  1552. }
  1553. }]);
  1554. return MediaElementWebAudio;
  1555. }(_mediaelement.default);
  1556. exports.default = MediaElementWebAudio;
  1557. module.exports = exports.default;
  1558. /***/ }),
  1559. /***/ "./src/mediaelement.js":
  1560. /*!*****************************!*\
  1561. !*** ./src/mediaelement.js ***!
  1562. \*****************************/
  1563. /*! no static exports found */
  1564. /***/ (function(module, exports, __webpack_require__) {
  1565. "use strict";
  1566. Object.defineProperty(exports, "__esModule", {
  1567. value: true
  1568. });
  1569. exports.default = void 0;
  1570. var _webaudio = _interopRequireDefault(__webpack_require__(/*! ./webaudio */ "./src/webaudio.js"));
  1571. var util = _interopRequireWildcard(__webpack_require__(/*! ./util */ "./src/util/index.js"));
  1572. function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; }
  1573. function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
  1574. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  1575. function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
  1576. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  1577. function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
  1578. function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
  1579. function _get(target, property, receiver) { if (typeof Reflect !== "undefined" && Reflect.get) { _get = Reflect.get; } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(receiver); } return desc.value; }; } return _get(target, property, receiver || target); }
  1580. function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; }
  1581. function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
  1582. function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
  1583. function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
  1584. function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
  1585. function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
  1586. function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
  1587. function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
  1588. /**
  1589. * MediaElement backend
  1590. */
  1591. var MediaElement = /*#__PURE__*/function (_WebAudio) {
  1592. _inherits(MediaElement, _WebAudio);
  1593. var _super = _createSuper(MediaElement);
  1594. /**
  1595. * Construct the backend
  1596. *
  1597. * @param {WavesurferParams} params Wavesurfer parameters
  1598. */
  1599. function MediaElement(params) {
  1600. var _this;
  1601. _classCallCheck(this, MediaElement);
  1602. _this = _super.call(this, params);
  1603. /** @private */
  1604. _this.params = params;
  1605. /**
  1606. * Initially a dummy media element to catch errors. Once `_load` is
  1607. * called, this will contain the actual `HTMLMediaElement`.
  1608. * @private
  1609. */
  1610. _this.media = {
  1611. currentTime: 0,
  1612. duration: 0,
  1613. paused: true,
  1614. playbackRate: 1,
  1615. play: function play() {},
  1616. pause: function pause() {},
  1617. volume: 0
  1618. };
  1619. /** @private */
  1620. _this.mediaType = params.mediaType.toLowerCase();
  1621. /** @private */
  1622. _this.elementPosition = params.elementPosition;
  1623. /** @private */
  1624. _this.peaks = null;
  1625. /** @private */
  1626. _this.playbackRate = 1;
  1627. /** @private */
  1628. _this.volume = 1;
  1629. /** @private */
  1630. _this.isMuted = false;
  1631. /** @private */
  1632. _this.buffer = null;
  1633. /** @private */
  1634. _this.onPlayEnd = null;
  1635. /** @private */
  1636. _this.mediaListeners = {};
  1637. return _this;
  1638. }
  1639. /**
  1640. * Initialise the backend, called in `wavesurfer.createBackend()`
  1641. */
  1642. _createClass(MediaElement, [{
  1643. key: "init",
  1644. value: function init() {
  1645. this.setPlaybackRate(this.params.audioRate);
  1646. this.createTimer();
  1647. }
  1648. /**
  1649. * Attach event listeners to media element.
  1650. */
  1651. }, {
  1652. key: "_setupMediaListeners",
  1653. value: function _setupMediaListeners() {
  1654. var _this2 = this;
  1655. this.mediaListeners.error = function () {
  1656. _this2.fireEvent('error', 'Error loading media element');
  1657. };
  1658. this.mediaListeners.canplay = function () {
  1659. _this2.fireEvent('canplay');
  1660. };
  1661. this.mediaListeners.ended = function () {
  1662. _this2.fireEvent('finish');
  1663. }; // listen to and relay play, pause and seeked events to enable
  1664. // playback control from the external media element
  1665. this.mediaListeners.play = function () {
  1666. _this2.fireEvent('play');
  1667. };
  1668. this.mediaListeners.pause = function () {
  1669. _this2.fireEvent('pause');
  1670. };
  1671. this.mediaListeners.seeked = function (event) {
  1672. _this2.fireEvent('seek');
  1673. };
  1674. this.mediaListeners.volumechange = function (event) {
  1675. _this2.isMuted = _this2.media.muted;
  1676. if (_this2.isMuted) {
  1677. _this2.volume = 0;
  1678. } else {
  1679. _this2.volume = _this2.media.volume;
  1680. }
  1681. _this2.fireEvent('volume');
  1682. }; // reset event listeners
  1683. Object.keys(this.mediaListeners).forEach(function (id) {
  1684. _this2.media.removeEventListener(id, _this2.mediaListeners[id]);
  1685. _this2.media.addEventListener(id, _this2.mediaListeners[id]);
  1686. });
  1687. }
  1688. /**
  1689. * Create a timer to provide a more precise `audioprocess` event.
  1690. */
  1691. }, {
  1692. key: "createTimer",
  1693. value: function createTimer() {
  1694. var _this3 = this;
  1695. var onAudioProcess = function onAudioProcess() {
  1696. if (_this3.isPaused()) {
  1697. return;
  1698. }
  1699. _this3.fireEvent('audioprocess', _this3.getCurrentTime()); // Call again in the next frame
  1700. util.frame(onAudioProcess)();
  1701. };
  1702. this.on('play', onAudioProcess); // Update the progress one more time to prevent it from being stuck in
  1703. // case of lower framerates
  1704. this.on('pause', function () {
  1705. _this3.fireEvent('audioprocess', _this3.getCurrentTime());
  1706. });
  1707. }
  1708. /**
  1709. * Create media element with url as its source,
  1710. * and append to container element.
  1711. *
  1712. * @param {string} url Path to media file
  1713. * @param {HTMLElement} container HTML element
  1714. * @param {number[]|Number.<Array[]>} peaks Array of peak data
  1715. * @param {string} preload HTML 5 preload attribute value
  1716. * @throws Will throw an error if the `url` argument is not a valid media
  1717. * element.
  1718. */
  1719. }, {
  1720. key: "load",
  1721. value: function load(url, container, peaks, preload) {
  1722. var media = document.createElement(this.mediaType);
  1723. media.controls = this.params.mediaControls;
  1724. media.autoplay = this.params.autoplay || false;
  1725. media.preload = preload == null ? 'auto' : preload;
  1726. media.src = url;
  1727. media.style.width = '100%';
  1728. var prevMedia = container.querySelector(this.mediaType);
  1729. if (prevMedia) {
  1730. container.removeChild(prevMedia);
  1731. }
  1732. container.appendChild(media);
  1733. this._load(media, peaks, preload);
  1734. }
  1735. /**
  1736. * Load existing media element.
  1737. *
  1738. * @param {HTMLMediaElement} elt HTML5 Audio or Video element
  1739. * @param {number[]|Number.<Array[]>} peaks Array of peak data
  1740. */
  1741. }, {
  1742. key: "loadElt",
  1743. value: function loadElt(elt, peaks) {
  1744. elt.controls = this.params.mediaControls;
  1745. elt.autoplay = this.params.autoplay || false;
  1746. this._load(elt, peaks, elt.preload);
  1747. }
  1748. /**
  1749. * Method called by both `load` (from url)
  1750. * and `loadElt` (existing media element) methods.
  1751. *
  1752. * @param {HTMLMediaElement} media HTML5 Audio or Video element
  1753. * @param {number[]|Number.<Array[]>} peaks Array of peak data
  1754. * @param {string} preload HTML 5 preload attribute value
  1755. * @throws Will throw an error if the `media` argument is not a valid media
  1756. * element.
  1757. * @private
  1758. */
  1759. }, {
  1760. key: "_load",
  1761. value: function _load(media, peaks, preload) {
  1762. // verify media element is valid
  1763. if (!(media instanceof HTMLMediaElement) || typeof media.addEventListener === 'undefined') {
  1764. throw new Error('media parameter is not a valid media element');
  1765. } // load must be called manually on iOS, otherwise peaks won't draw
  1766. // until a user interaction triggers load --> 'ready' event
  1767. //
  1768. // note that we avoid calling media.load here when given peaks and preload == 'none'
  1769. // as this almost always triggers some browser fetch of the media.
  1770. if (typeof media.load == 'function' && !(peaks && preload == 'none')) {
  1771. // Resets the media element and restarts the media resource. Any
  1772. // pending events are discarded. How much media data is fetched is
  1773. // still affected by the preload attribute.
  1774. media.load();
  1775. }
  1776. this.media = media;
  1777. this._setupMediaListeners();
  1778. this.peaks = peaks;
  1779. this.onPlayEnd = null;
  1780. this.buffer = null;
  1781. this.isMuted = media.muted;
  1782. this.setPlaybackRate(this.playbackRate);
  1783. this.setVolume(this.volume);
  1784. }
  1785. /**
  1786. * Used by `wavesurfer.isPlaying()` and `wavesurfer.playPause()`
  1787. *
  1788. * @return {boolean} Media paused or not
  1789. */
  1790. }, {
  1791. key: "isPaused",
  1792. value: function isPaused() {
  1793. return !this.media || this.media.paused;
  1794. }
  1795. /**
  1796. * Used by `wavesurfer.getDuration()`
  1797. *
  1798. * @return {number} Duration
  1799. */
  1800. }, {
  1801. key: "getDuration",
  1802. value: function getDuration() {
  1803. if (this.explicitDuration) {
  1804. return this.explicitDuration;
  1805. }
  1806. var duration = (this.buffer || this.media).duration;
  1807. if (duration >= Infinity) {
  1808. // streaming audio
  1809. duration = this.media.seekable.end(0);
  1810. }
  1811. return duration;
  1812. }
  1813. /**
  1814. * Returns the current time in seconds relative to the audio-clip's
  1815. * duration.
  1816. *
  1817. * @return {number} Current time
  1818. */
  1819. }, {
  1820. key: "getCurrentTime",
  1821. value: function getCurrentTime() {
  1822. return this.media && this.media.currentTime;
  1823. }
  1824. /**
  1825. * Get the position from 0 to 1
  1826. *
  1827. * @return {number} Current position
  1828. */
  1829. }, {
  1830. key: "getPlayedPercents",
  1831. value: function getPlayedPercents() {
  1832. return this.getCurrentTime() / this.getDuration() || 0;
  1833. }
  1834. /**
  1835. * Get the audio source playback rate.
  1836. *
  1837. * @return {number} Playback rate
  1838. */
  1839. }, {
  1840. key: "getPlaybackRate",
  1841. value: function getPlaybackRate() {
  1842. return this.playbackRate || this.media.playbackRate;
  1843. }
  1844. /**
  1845. * Set the audio source playback rate.
  1846. *
  1847. * @param {number} value Playback rate
  1848. */
  1849. }, {
  1850. key: "setPlaybackRate",
  1851. value: function setPlaybackRate(value) {
  1852. this.playbackRate = value || 1;
  1853. this.media.playbackRate = this.playbackRate;
  1854. }
  1855. /**
  1856. * Used by `wavesurfer.seekTo()`
  1857. *
  1858. * @param {number} start Position to start at in seconds
  1859. */
  1860. }, {
  1861. key: "seekTo",
  1862. value: function seekTo(start) {
  1863. if (start != null) {
  1864. this.media.currentTime = start;
  1865. }
  1866. this.clearPlayEnd();
  1867. }
  1868. /**
  1869. * Plays the loaded audio region.
  1870. *
  1871. * @param {number} start Start offset in seconds, relative to the beginning
  1872. * of a clip.
  1873. * @param {number} end When to stop, relative to the beginning of a clip.
  1874. * @emits MediaElement#play
  1875. * @return {Promise} Result
  1876. */
  1877. }, {
  1878. key: "play",
  1879. value: function play(start, end) {
  1880. this.seekTo(start);
  1881. var promise = this.media.play();
  1882. end && this.setPlayEnd(end);
  1883. return promise;
  1884. }
  1885. /**
  1886. * Pauses the loaded audio.
  1887. *
  1888. * @emits MediaElement#pause
  1889. * @return {Promise} Result
  1890. */
  1891. }, {
  1892. key: "pause",
  1893. value: function pause() {
  1894. var promise;
  1895. if (this.media) {
  1896. promise = this.media.pause();
  1897. }
  1898. this.clearPlayEnd();
  1899. return promise;
  1900. }
  1901. /**
  1902. * Set the play end
  1903. *
  1904. * @param {number} end Where to end
  1905. */
  1906. }, {
  1907. key: "setPlayEnd",
  1908. value: function setPlayEnd(end) {
  1909. var _this4 = this;
  1910. this.clearPlayEnd();
  1911. this._onPlayEnd = function (time) {
  1912. if (time >= end) {
  1913. _this4.pause();
  1914. _this4.seekTo(end);
  1915. }
  1916. };
  1917. this.on('audioprocess', this._onPlayEnd);
  1918. }
  1919. /** @private */
  1920. }, {
  1921. key: "clearPlayEnd",
  1922. value: function clearPlayEnd() {
  1923. if (this._onPlayEnd) {
  1924. this.un('audioprocess', this._onPlayEnd);
  1925. this._onPlayEnd = null;
  1926. }
  1927. }
  1928. /**
  1929. * Compute the max and min value of the waveform when broken into
  1930. * <length> subranges.
  1931. *
  1932. * @param {number} length How many subranges to break the waveform into.
  1933. * @param {number} first First sample in the required range.
  1934. * @param {number} last Last sample in the required range.
  1935. * @return {number[]|Number.<Array[]>} Array of 2*<length> peaks or array of
  1936. * arrays of peaks consisting of (max, min) values for each subrange.
  1937. */
  1938. }, {
  1939. key: "getPeaks",
  1940. value: function getPeaks(length, first, last) {
  1941. if (this.buffer) {
  1942. return _get(_getPrototypeOf(MediaElement.prototype), "getPeaks", this).call(this, length, first, last);
  1943. }
  1944. return this.peaks || [];
  1945. }
  1946. /**
  1947. * Set the sink id for the media player
  1948. *
  1949. * @param {string} deviceId String value representing audio device id.
  1950. * @returns {Promise} A Promise that resolves to `undefined` when there
  1951. * are no errors.
  1952. */
  1953. }, {
  1954. key: "setSinkId",
  1955. value: function setSinkId(deviceId) {
  1956. if (deviceId) {
  1957. if (!this.media.setSinkId) {
  1958. return Promise.reject(new Error('setSinkId is not supported in your browser'));
  1959. }
  1960. return this.media.setSinkId(deviceId);
  1961. }
  1962. return Promise.reject(new Error('Invalid deviceId: ' + deviceId));
  1963. }
  1964. /**
  1965. * Get the current volume
  1966. *
  1967. * @return {number} value A floating point value between 0 and 1.
  1968. */
  1969. }, {
  1970. key: "getVolume",
  1971. value: function getVolume() {
  1972. return this.volume;
  1973. }
  1974. /**
  1975. * Set the audio volume
  1976. *
  1977. * @param {number} value A floating point value between 0 and 1.
  1978. */
  1979. }, {
  1980. key: "setVolume",
  1981. value: function setVolume(value) {
  1982. this.volume = value; // no need to change when it's already at that volume
  1983. if (this.media.volume !== this.volume) {
  1984. this.media.volume = this.volume;
  1985. }
  1986. }
  1987. /**
  1988. * Enable or disable muted audio
  1989. *
  1990. * @since 4.0.0
  1991. * @param {boolean} muted Specify `true` to mute audio.
  1992. */
  1993. }, {
  1994. key: "setMute",
  1995. value: function setMute(muted) {
  1996. // This causes a volume change to be emitted too through the
  1997. // volumechange event listener.
  1998. this.isMuted = this.media.muted = muted;
  1999. }
  2000. /**
  2001. * This is called when wavesurfer is destroyed
  2002. *
  2003. */
  2004. }, {
  2005. key: "destroy",
  2006. value: function destroy() {
  2007. var _this5 = this;
  2008. this.pause();
  2009. this.unAll();
  2010. this.destroyed = true; // cleanup media event listeners
  2011. Object.keys(this.mediaListeners).forEach(function (id) {
  2012. if (_this5.media) {
  2013. _this5.media.removeEventListener(id, _this5.mediaListeners[id]);
  2014. }
  2015. });
  2016. if (this.params.removeMediaElementOnDestroy && this.media && this.media.parentNode) {
  2017. this.media.parentNode.removeChild(this.media);
  2018. }
  2019. this.media = null;
  2020. }
  2021. }]);
  2022. return MediaElement;
  2023. }(_webaudio.default);
  2024. exports.default = MediaElement;
  2025. module.exports = exports.default;
  2026. /***/ }),
  2027. /***/ "./src/peakcache.js":
  2028. /*!**************************!*\
  2029. !*** ./src/peakcache.js ***!
  2030. \**************************/
  2031. /*! no static exports found */
  2032. /***/ (function(module, exports, __webpack_require__) {
  2033. "use strict";
  2034. Object.defineProperty(exports, "__esModule", {
  2035. value: true
  2036. });
  2037. exports.default = void 0;
  2038. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  2039. function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
  2040. function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
  2041. /**
  2042. * Caches the decoded peaks data to improve rendering speed for large audio
  2043. *
  2044. * Is used if the option parameter `partialRender` is set to `true`
  2045. */
  2046. var PeakCache = /*#__PURE__*/function () {
  2047. /**
  2048. * Instantiate cache
  2049. */
  2050. function PeakCache() {
  2051. _classCallCheck(this, PeakCache);
  2052. this.clearPeakCache();
  2053. }
  2054. /**
  2055. * Empty the cache
  2056. */
  2057. _createClass(PeakCache, [{
  2058. key: "clearPeakCache",
  2059. value: function clearPeakCache() {
  2060. /**
  2061. * Flat array with entries that are always in pairs to mark the
  2062. * beginning and end of each subrange. This is a convenience so we can
  2063. * iterate over the pairs for easy set difference operations.
  2064. * @private
  2065. */
  2066. this.peakCacheRanges = [];
  2067. /**
  2068. * Length of the entire cachable region, used for resetting the cache
  2069. * when this changes (zoom events, for instance).
  2070. * @private
  2071. */
  2072. this.peakCacheLength = -1;
  2073. }
  2074. /**
  2075. * Add a range of peaks to the cache
  2076. *
  2077. * @param {number} length The length of the range
  2078. * @param {number} start The x offset of the start of the range
  2079. * @param {number} end The x offset of the end of the range
  2080. * @return {Number.<Array[]>} Array with arrays of numbers
  2081. */
  2082. }, {
  2083. key: "addRangeToPeakCache",
  2084. value: function addRangeToPeakCache(length, start, end) {
  2085. if (length != this.peakCacheLength) {
  2086. this.clearPeakCache();
  2087. this.peakCacheLength = length;
  2088. } // Return ranges that weren't in the cache before the call.
  2089. var uncachedRanges = [];
  2090. var i = 0; // Skip ranges before the current start.
  2091. while (i < this.peakCacheRanges.length && this.peakCacheRanges[i] < start) {
  2092. i++;
  2093. } // If |i| is even, |start| falls after an existing range. Otherwise,
  2094. // |start| falls between an existing range, and the uncached region
  2095. // starts when we encounter the next node in |peakCacheRanges| or
  2096. // |end|, whichever comes first.
  2097. if (i % 2 == 0) {
  2098. uncachedRanges.push(start);
  2099. }
  2100. while (i < this.peakCacheRanges.length && this.peakCacheRanges[i] <= end) {
  2101. uncachedRanges.push(this.peakCacheRanges[i]);
  2102. i++;
  2103. } // If |i| is even, |end| is after all existing ranges.
  2104. if (i % 2 == 0) {
  2105. uncachedRanges.push(end);
  2106. } // Filter out the 0-length ranges.
  2107. uncachedRanges = uncachedRanges.filter(function (item, pos, arr) {
  2108. if (pos == 0) {
  2109. return item != arr[pos + 1];
  2110. } else if (pos == arr.length - 1) {
  2111. return item != arr[pos - 1];
  2112. }
  2113. return item != arr[pos - 1] && item != arr[pos + 1];
  2114. }); // Merge the two ranges together, uncachedRanges will either contain
  2115. // wholly new points, or duplicates of points in peakCacheRanges. If
  2116. // duplicates are detected, remove both and extend the range.
  2117. this.peakCacheRanges = this.peakCacheRanges.concat(uncachedRanges);
  2118. this.peakCacheRanges = this.peakCacheRanges.sort(function (a, b) {
  2119. return a - b;
  2120. }).filter(function (item, pos, arr) {
  2121. if (pos == 0) {
  2122. return item != arr[pos + 1];
  2123. } else if (pos == arr.length - 1) {
  2124. return item != arr[pos - 1];
  2125. }
  2126. return item != arr[pos - 1] && item != arr[pos + 1];
  2127. }); // Push the uncached ranges into an array of arrays for ease of
  2128. // iteration in the functions that call this.
  2129. var uncachedRangePairs = [];
  2130. for (i = 0; i < uncachedRanges.length; i += 2) {
  2131. uncachedRangePairs.push([uncachedRanges[i], uncachedRanges[i + 1]]);
  2132. }
  2133. return uncachedRangePairs;
  2134. }
  2135. /**
  2136. * For testing
  2137. *
  2138. * @return {Number.<Array[]>} Array with arrays of numbers
  2139. */
  2140. }, {
  2141. key: "getCacheRanges",
  2142. value: function getCacheRanges() {
  2143. var peakCacheRangePairs = [];
  2144. var i;
  2145. for (i = 0; i < this.peakCacheRanges.length; i += 2) {
  2146. peakCacheRangePairs.push([this.peakCacheRanges[i], this.peakCacheRanges[i + 1]]);
  2147. }
  2148. return peakCacheRangePairs;
  2149. }
  2150. }]);
  2151. return PeakCache;
  2152. }();
  2153. exports.default = PeakCache;
  2154. module.exports = exports.default;
  2155. /***/ }),
  2156. /***/ "./src/util/clamp.js":
  2157. /*!***************************!*\
  2158. !*** ./src/util/clamp.js ***!
  2159. \***************************/
  2160. /*! no static exports found */
  2161. /***/ (function(module, exports, __webpack_require__) {
  2162. "use strict";
  2163. Object.defineProperty(exports, "__esModule", {
  2164. value: true
  2165. });
  2166. exports.default = clamp;
  2167. /**
  2168. * Returns a number limited to the given range.
  2169. *
  2170. * @param {number} val The number to be limited to a range
  2171. * @param {number} min The lower boundary of the limit range
  2172. * @param {number} max The upper boundary of the limit range
  2173. * @returns {number} A number in the range [min, max]
  2174. */
  2175. function clamp(val, min, max) {
  2176. return Math.min(Math.max(min, val), max);
  2177. }
  2178. module.exports = exports.default;
  2179. /***/ }),
  2180. /***/ "./src/util/fetch.js":
  2181. /*!***************************!*\
  2182. !*** ./src/util/fetch.js ***!
  2183. \***************************/
  2184. /*! no static exports found */
  2185. /***/ (function(module, exports, __webpack_require__) {
  2186. "use strict";
  2187. Object.defineProperty(exports, "__esModule", {
  2188. value: true
  2189. });
  2190. exports.default = fetchFile;
  2191. var _observer = _interopRequireDefault(__webpack_require__(/*! ./observer */ "./src/util/observer.js"));
  2192. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  2193. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  2194. function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
  2195. function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
  2196. var ProgressHandler = /*#__PURE__*/function () {
  2197. /**
  2198. * Instantiate ProgressHandler
  2199. *
  2200. * @param {Observer} instance The `fetchFile` observer instance.
  2201. * @param {Number} contentLength Content length.
  2202. * @param {Response} response Response object.
  2203. */
  2204. function ProgressHandler(instance, contentLength, response) {
  2205. _classCallCheck(this, ProgressHandler);
  2206. this.instance = instance;
  2207. this.instance._reader = response.body.getReader();
  2208. this.total = parseInt(contentLength, 10);
  2209. this.loaded = 0;
  2210. }
  2211. /**
  2212. * A method that is called once, immediately after the `ReadableStream``
  2213. * is constructed.
  2214. *
  2215. * @param {ReadableStreamDefaultController} controller Controller instance
  2216. * used to control the stream.
  2217. */
  2218. _createClass(ProgressHandler, [{
  2219. key: "start",
  2220. value: function start(controller) {
  2221. var _this = this;
  2222. var read = function read() {
  2223. // instance._reader.read() returns a promise that resolves
  2224. // when a value has been received
  2225. _this.instance._reader.read().then(function (_ref) {
  2226. var done = _ref.done,
  2227. value = _ref.value;
  2228. // result objects contain two properties:
  2229. // done - true if the stream has already given you all its data.
  2230. // value - some data. Always undefined when done is true.
  2231. if (done) {
  2232. // ensure onProgress called when content-length=0
  2233. if (_this.total === 0) {
  2234. _this.instance.onProgress.call(_this.instance, {
  2235. loaded: _this.loaded,
  2236. total: _this.total,
  2237. lengthComputable: false
  2238. });
  2239. } // no more data needs to be consumed, close the stream
  2240. controller.close();
  2241. return;
  2242. }
  2243. _this.loaded += value.byteLength;
  2244. _this.instance.onProgress.call(_this.instance, {
  2245. loaded: _this.loaded,
  2246. total: _this.total,
  2247. lengthComputable: !(_this.total === 0)
  2248. }); // enqueue the next data chunk into our target stream
  2249. controller.enqueue(value);
  2250. read();
  2251. }).catch(function (error) {
  2252. controller.error(error);
  2253. });
  2254. };
  2255. read();
  2256. }
  2257. }]);
  2258. return ProgressHandler;
  2259. }();
  2260. /**
  2261. * Load a file using `fetch`.
  2262. *
  2263. * @param {object} options Request options to use. See example below.
  2264. * @returns {Observer} Observer instance
  2265. * @example
  2266. * // default options
  2267. * let options = {
  2268. * url: undefined,
  2269. * method: 'GET',
  2270. * mode: 'cors',
  2271. * credentials: 'same-origin',
  2272. * cache: 'default',
  2273. * responseType: 'json',
  2274. * requestHeaders: [],
  2275. * redirect: 'follow',
  2276. * referrer: 'client'
  2277. * };
  2278. *
  2279. * // override some options
  2280. * options.url = '../media/demo.wav';
  2281. * // available types: 'arraybuffer', 'blob', 'json' or 'text'
  2282. * options.responseType = 'arraybuffer';
  2283. *
  2284. * // make fetch call
  2285. * let request = util.fetchFile(options);
  2286. *
  2287. * // listen for events
  2288. * request.on('progress', e => {
  2289. * console.log('progress', e);
  2290. * });
  2291. *
  2292. * request.on('success', data => {
  2293. * console.log('success!', data);
  2294. * });
  2295. *
  2296. * request.on('error', e => {
  2297. * console.warn('fetchFile error: ', e);
  2298. * });
  2299. */
  2300. function fetchFile(options) {
  2301. if (!options) {
  2302. throw new Error('fetch options missing');
  2303. } else if (!options.url) {
  2304. throw new Error('fetch url missing');
  2305. }
  2306. var instance = new _observer.default();
  2307. var fetchHeaders = new Headers();
  2308. var fetchRequest = new Request(options.url); // add ability to abort
  2309. instance.controller = new AbortController(); // check if headers have to be added
  2310. if (options && options.requestHeaders) {
  2311. // add custom request headers
  2312. options.requestHeaders.forEach(function (header) {
  2313. fetchHeaders.append(header.key, header.value);
  2314. });
  2315. } // parse fetch options
  2316. var responseType = options.responseType || 'json';
  2317. var fetchOptions = {
  2318. method: options.method || 'GET',
  2319. headers: fetchHeaders,
  2320. mode: options.mode || 'cors',
  2321. credentials: options.credentials || 'same-origin',
  2322. cache: options.cache || 'default',
  2323. redirect: options.redirect || 'follow',
  2324. referrer: options.referrer || 'client',
  2325. signal: instance.controller.signal
  2326. };
  2327. fetch(fetchRequest, fetchOptions).then(function (response) {
  2328. // store response reference
  2329. instance.response = response;
  2330. var progressAvailable = true;
  2331. if (!response.body) {
  2332. // ReadableStream is not yet supported in this browser
  2333. // see https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream
  2334. progressAvailable = false;
  2335. } // Server must send CORS header "Access-Control-Expose-Headers: content-length"
  2336. var contentLength = response.headers.get('content-length');
  2337. if (contentLength === null) {
  2338. // Content-Length server response header missing.
  2339. // Don't evaluate download progress if we can't compare against a total size
  2340. // see https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Access-Control-Expose-Headers
  2341. progressAvailable = false;
  2342. }
  2343. if (!progressAvailable) {
  2344. // not able to check download progress so skip it
  2345. return response;
  2346. } // fire progress event when during load
  2347. instance.onProgress = function (e) {
  2348. instance.fireEvent('progress', e);
  2349. };
  2350. return new Response(new ReadableStream(new ProgressHandler(instance, contentLength, response)), fetchOptions);
  2351. }).then(function (response) {
  2352. var errMsg;
  2353. if (response.ok) {
  2354. switch (responseType) {
  2355. case 'arraybuffer':
  2356. return response.arrayBuffer();
  2357. case 'json':
  2358. return response.json();
  2359. case 'blob':
  2360. return response.blob();
  2361. case 'text':
  2362. return response.text();
  2363. default:
  2364. errMsg = 'Unknown responseType: ' + responseType;
  2365. break;
  2366. }
  2367. }
  2368. if (!errMsg) {
  2369. errMsg = 'HTTP error status: ' + response.status;
  2370. }
  2371. throw new Error(errMsg);
  2372. }).then(function (response) {
  2373. instance.fireEvent('success', response);
  2374. }).catch(function (error) {
  2375. instance.fireEvent('error', error);
  2376. }); // return the fetch request
  2377. instance.fetchRequest = fetchRequest;
  2378. return instance;
  2379. }
  2380. module.exports = exports.default;
  2381. /***/ }),
  2382. /***/ "./src/util/frame.js":
  2383. /*!***************************!*\
  2384. !*** ./src/util/frame.js ***!
  2385. \***************************/
  2386. /*! no static exports found */
  2387. /***/ (function(module, exports, __webpack_require__) {
  2388. "use strict";
  2389. Object.defineProperty(exports, "__esModule", {
  2390. value: true
  2391. });
  2392. exports.default = frame;
  2393. var _requestAnimationFrame = _interopRequireDefault(__webpack_require__(/*! ./request-animation-frame */ "./src/util/request-animation-frame.js"));
  2394. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  2395. /**
  2396. * Create a function which will be called at the next requestAnimationFrame
  2397. * cycle
  2398. *
  2399. * @param {function} func The function to call
  2400. *
  2401. * @return {func} The function wrapped within a requestAnimationFrame
  2402. */
  2403. function frame(func) {
  2404. return function () {
  2405. for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
  2406. args[_key] = arguments[_key];
  2407. }
  2408. return (0, _requestAnimationFrame.default)(function () {
  2409. return func.apply(void 0, args);
  2410. });
  2411. };
  2412. }
  2413. module.exports = exports.default;
  2414. /***/ }),
  2415. /***/ "./src/util/get-id.js":
  2416. /*!****************************!*\
  2417. !*** ./src/util/get-id.js ***!
  2418. \****************************/
  2419. /*! no static exports found */
  2420. /***/ (function(module, exports, __webpack_require__) {
  2421. "use strict";
  2422. Object.defineProperty(exports, "__esModule", {
  2423. value: true
  2424. });
  2425. exports.default = getId;
  2426. /**
  2427. * Get a random prefixed ID
  2428. *
  2429. * @param {String} prefix Prefix to use. Default is `'wavesurfer_'`.
  2430. * @returns {String} Random prefixed ID
  2431. * @example
  2432. * console.log(getId()); // logs 'wavesurfer_b5pors4ru6g'
  2433. *
  2434. * let prefix = 'foo-';
  2435. * console.log(getId(prefix)); // logs 'foo-b5pors4ru6g'
  2436. */
  2437. function getId(prefix) {
  2438. if (prefix === undefined) {
  2439. prefix = 'wavesurfer_';
  2440. }
  2441. return prefix + Math.random().toString(32).substring(2);
  2442. }
  2443. module.exports = exports.default;
  2444. /***/ }),
  2445. /***/ "./src/util/index.js":
  2446. /*!***************************!*\
  2447. !*** ./src/util/index.js ***!
  2448. \***************************/
  2449. /*! no static exports found */
  2450. /***/ (function(module, exports, __webpack_require__) {
  2451. "use strict";
  2452. Object.defineProperty(exports, "__esModule", {
  2453. value: true
  2454. });
  2455. Object.defineProperty(exports, "getId", {
  2456. enumerable: true,
  2457. get: function get() {
  2458. return _getId.default;
  2459. }
  2460. });
  2461. Object.defineProperty(exports, "max", {
  2462. enumerable: true,
  2463. get: function get() {
  2464. return _max.default;
  2465. }
  2466. });
  2467. Object.defineProperty(exports, "min", {
  2468. enumerable: true,
  2469. get: function get() {
  2470. return _min.default;
  2471. }
  2472. });
  2473. Object.defineProperty(exports, "Observer", {
  2474. enumerable: true,
  2475. get: function get() {
  2476. return _observer.default;
  2477. }
  2478. });
  2479. Object.defineProperty(exports, "style", {
  2480. enumerable: true,
  2481. get: function get() {
  2482. return _style.default;
  2483. }
  2484. });
  2485. Object.defineProperty(exports, "requestAnimationFrame", {
  2486. enumerable: true,
  2487. get: function get() {
  2488. return _requestAnimationFrame.default;
  2489. }
  2490. });
  2491. Object.defineProperty(exports, "frame", {
  2492. enumerable: true,
  2493. get: function get() {
  2494. return _frame.default;
  2495. }
  2496. });
  2497. Object.defineProperty(exports, "debounce", {
  2498. enumerable: true,
  2499. get: function get() {
  2500. return _debounce.default;
  2501. }
  2502. });
  2503. Object.defineProperty(exports, "preventClick", {
  2504. enumerable: true,
  2505. get: function get() {
  2506. return _preventClick.default;
  2507. }
  2508. });
  2509. Object.defineProperty(exports, "fetchFile", {
  2510. enumerable: true,
  2511. get: function get() {
  2512. return _fetch.default;
  2513. }
  2514. });
  2515. Object.defineProperty(exports, "clamp", {
  2516. enumerable: true,
  2517. get: function get() {
  2518. return _clamp.default;
  2519. }
  2520. });
  2521. var _getId = _interopRequireDefault(__webpack_require__(/*! ./get-id */ "./src/util/get-id.js"));
  2522. var _max = _interopRequireDefault(__webpack_require__(/*! ./max */ "./src/util/max.js"));
  2523. var _min = _interopRequireDefault(__webpack_require__(/*! ./min */ "./src/util/min.js"));
  2524. var _observer = _interopRequireDefault(__webpack_require__(/*! ./observer */ "./src/util/observer.js"));
  2525. var _style = _interopRequireDefault(__webpack_require__(/*! ./style */ "./src/util/style.js"));
  2526. var _requestAnimationFrame = _interopRequireDefault(__webpack_require__(/*! ./request-animation-frame */ "./src/util/request-animation-frame.js"));
  2527. var _frame = _interopRequireDefault(__webpack_require__(/*! ./frame */ "./src/util/frame.js"));
  2528. var _debounce = _interopRequireDefault(__webpack_require__(/*! debounce */ "./node_modules/debounce/index.js"));
  2529. var _preventClick = _interopRequireDefault(__webpack_require__(/*! ./prevent-click */ "./src/util/prevent-click.js"));
  2530. var _fetch = _interopRequireDefault(__webpack_require__(/*! ./fetch */ "./src/util/fetch.js"));
  2531. var _clamp = _interopRequireDefault(__webpack_require__(/*! ./clamp */ "./src/util/clamp.js"));
  2532. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  2533. /***/ }),
  2534. /***/ "./src/util/max.js":
  2535. /*!*************************!*\
  2536. !*** ./src/util/max.js ***!
  2537. \*************************/
  2538. /*! no static exports found */
  2539. /***/ (function(module, exports, __webpack_require__) {
  2540. "use strict";
  2541. Object.defineProperty(exports, "__esModule", {
  2542. value: true
  2543. });
  2544. exports.default = max;
  2545. /**
  2546. * Get the largest value
  2547. *
  2548. * @param {Array} values Array of numbers
  2549. * @returns {Number} Largest number found
  2550. * @example console.log(max([1, 2, 3])); // logs 3
  2551. */
  2552. function max(values) {
  2553. var largest = -Infinity;
  2554. Object.keys(values).forEach(function (i) {
  2555. if (values[i] > largest) {
  2556. largest = values[i];
  2557. }
  2558. });
  2559. return largest;
  2560. }
  2561. module.exports = exports.default;
  2562. /***/ }),
  2563. /***/ "./src/util/min.js":
  2564. /*!*************************!*\
  2565. !*** ./src/util/min.js ***!
  2566. \*************************/
  2567. /*! no static exports found */
  2568. /***/ (function(module, exports, __webpack_require__) {
  2569. "use strict";
  2570. Object.defineProperty(exports, "__esModule", {
  2571. value: true
  2572. });
  2573. exports.default = min;
  2574. /**
  2575. * Get the smallest value
  2576. *
  2577. * @param {Array} values Array of numbers
  2578. * @returns {Number} Smallest number found
  2579. * @example console.log(min([1, 2, 3])); // logs 1
  2580. */
  2581. function min(values) {
  2582. var smallest = Number(Infinity);
  2583. Object.keys(values).forEach(function (i) {
  2584. if (values[i] < smallest) {
  2585. smallest = values[i];
  2586. }
  2587. });
  2588. return smallest;
  2589. }
  2590. module.exports = exports.default;
  2591. /***/ }),
  2592. /***/ "./src/util/observer.js":
  2593. /*!******************************!*\
  2594. !*** ./src/util/observer.js ***!
  2595. \******************************/
  2596. /*! no static exports found */
  2597. /***/ (function(module, exports, __webpack_require__) {
  2598. "use strict";
  2599. Object.defineProperty(exports, "__esModule", {
  2600. value: true
  2601. });
  2602. exports.default = void 0;
  2603. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  2604. function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
  2605. function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
  2606. /**
  2607. * @typedef {Object} ListenerDescriptor
  2608. * @property {string} name The name of the event
  2609. * @property {function} callback The callback
  2610. * @property {function} un The function to call to remove the listener
  2611. */
  2612. /**
  2613. * Observer class
  2614. */
  2615. var Observer = /*#__PURE__*/function () {
  2616. /**
  2617. * Instantiate Observer
  2618. */
  2619. function Observer() {
  2620. _classCallCheck(this, Observer);
  2621. /**
  2622. * @private
  2623. * @todo Initialise the handlers here already and remove the conditional
  2624. * assignment in `on()`
  2625. */
  2626. this._disabledEventEmissions = [];
  2627. this.handlers = null;
  2628. }
  2629. /**
  2630. * Attach a handler function for an event.
  2631. *
  2632. * @param {string} event Name of the event to listen to
  2633. * @param {function} fn The callback to trigger when the event is fired
  2634. * @return {ListenerDescriptor} The event descriptor
  2635. */
  2636. _createClass(Observer, [{
  2637. key: "on",
  2638. value: function on(event, fn) {
  2639. var _this = this;
  2640. if (!this.handlers) {
  2641. this.handlers = {};
  2642. }
  2643. var handlers = this.handlers[event];
  2644. if (!handlers) {
  2645. handlers = this.handlers[event] = [];
  2646. }
  2647. handlers.push(fn); // Return an event descriptor
  2648. return {
  2649. name: event,
  2650. callback: fn,
  2651. un: function un(e, fn) {
  2652. return _this.un(e, fn);
  2653. }
  2654. };
  2655. }
  2656. /**
  2657. * Remove an event handler.
  2658. *
  2659. * @param {string} event Name of the event the listener that should be
  2660. * removed listens to
  2661. * @param {function} fn The callback that should be removed
  2662. */
  2663. }, {
  2664. key: "un",
  2665. value: function un(event, fn) {
  2666. if (!this.handlers) {
  2667. return;
  2668. }
  2669. var handlers = this.handlers[event];
  2670. var i;
  2671. if (handlers) {
  2672. if (fn) {
  2673. for (i = handlers.length - 1; i >= 0; i--) {
  2674. if (handlers[i] == fn) {
  2675. handlers.splice(i, 1);
  2676. }
  2677. }
  2678. } else {
  2679. handlers.length = 0;
  2680. }
  2681. }
  2682. }
  2683. /**
  2684. * Remove all event handlers.
  2685. */
  2686. }, {
  2687. key: "unAll",
  2688. value: function unAll() {
  2689. this.handlers = null;
  2690. }
  2691. /**
  2692. * Attach a handler to an event. The handler is executed at most once per
  2693. * event type.
  2694. *
  2695. * @param {string} event The event to listen to
  2696. * @param {function} handler The callback that is only to be called once
  2697. * @return {ListenerDescriptor} The event descriptor
  2698. */
  2699. }, {
  2700. key: "once",
  2701. value: function once(event, handler) {
  2702. var _this2 = this;
  2703. var fn = function fn() {
  2704. for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
  2705. args[_key] = arguments[_key];
  2706. }
  2707. /* eslint-disable no-invalid-this */
  2708. handler.apply(_this2, args);
  2709. /* eslint-enable no-invalid-this */
  2710. setTimeout(function () {
  2711. _this2.un(event, fn);
  2712. }, 0);
  2713. };
  2714. return this.on(event, fn);
  2715. }
  2716. /**
  2717. * Disable firing a list of events by name. When specified, event handlers for any event type
  2718. * passed in here will not be called.
  2719. *
  2720. * @since 4.0.0
  2721. * @param {string[]} eventNames an array of event names to disable emissions for
  2722. * @example
  2723. * // disable seek and interaction events
  2724. * wavesurfer.setDisabledEventEmissions(['seek', 'interaction']);
  2725. */
  2726. }, {
  2727. key: "setDisabledEventEmissions",
  2728. value: function setDisabledEventEmissions(eventNames) {
  2729. this._disabledEventEmissions = eventNames;
  2730. }
  2731. /**
  2732. * plugins borrow part of this class without calling the constructor,
  2733. * so we have to be careful about _disabledEventEmissions
  2734. */
  2735. }, {
  2736. key: "_isDisabledEventEmission",
  2737. value: function _isDisabledEventEmission(event) {
  2738. return this._disabledEventEmissions && this._disabledEventEmissions.includes(event);
  2739. }
  2740. /**
  2741. * Manually fire an event
  2742. *
  2743. * @param {string} event The event to fire manually
  2744. * @param {...any} args The arguments with which to call the listeners
  2745. */
  2746. }, {
  2747. key: "fireEvent",
  2748. value: function fireEvent(event) {
  2749. for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
  2750. args[_key2 - 1] = arguments[_key2];
  2751. }
  2752. if (!this.handlers || this._isDisabledEventEmission(event)) {
  2753. return;
  2754. }
  2755. var handlers = this.handlers[event];
  2756. handlers && handlers.forEach(function (fn) {
  2757. fn.apply(void 0, args);
  2758. });
  2759. }
  2760. }]);
  2761. return Observer;
  2762. }();
  2763. exports.default = Observer;
  2764. module.exports = exports.default;
  2765. /***/ }),
  2766. /***/ "./src/util/prevent-click.js":
  2767. /*!***********************************!*\
  2768. !*** ./src/util/prevent-click.js ***!
  2769. \***********************************/
  2770. /*! no static exports found */
  2771. /***/ (function(module, exports, __webpack_require__) {
  2772. "use strict";
  2773. Object.defineProperty(exports, "__esModule", {
  2774. value: true
  2775. });
  2776. exports.default = preventClick;
  2777. /**
  2778. * Stops propagation of click event and removes event listener
  2779. *
  2780. * @private
  2781. * @param {object} event The click event
  2782. */
  2783. function preventClickHandler(event) {
  2784. event.stopPropagation();
  2785. document.body.removeEventListener('click', preventClickHandler, true);
  2786. }
  2787. /**
  2788. * Starts listening for click event and prevent propagation
  2789. *
  2790. * @param {object} values Values
  2791. */
  2792. function preventClick(values) {
  2793. document.body.addEventListener('click', preventClickHandler, true);
  2794. }
  2795. module.exports = exports.default;
  2796. /***/ }),
  2797. /***/ "./src/util/request-animation-frame.js":
  2798. /*!*********************************************!*\
  2799. !*** ./src/util/request-animation-frame.js ***!
  2800. \*********************************************/
  2801. /*! no static exports found */
  2802. /***/ (function(module, exports, __webpack_require__) {
  2803. "use strict";
  2804. Object.defineProperty(exports, "__esModule", {
  2805. value: true
  2806. });
  2807. exports.default = void 0;
  2808. /* eslint-disable valid-jsdoc */
  2809. /**
  2810. * Returns the `requestAnimationFrame` function for the browser, or a shim with
  2811. * `setTimeout` if the function is not found
  2812. *
  2813. * @return {function} Available `requestAnimationFrame` function for the browser
  2814. */
  2815. var _default = (window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback, element) {
  2816. return setTimeout(callback, 1000 / 60);
  2817. }).bind(window);
  2818. exports.default = _default;
  2819. module.exports = exports.default;
  2820. /***/ }),
  2821. /***/ "./src/util/style.js":
  2822. /*!***************************!*\
  2823. !*** ./src/util/style.js ***!
  2824. \***************************/
  2825. /*! no static exports found */
  2826. /***/ (function(module, exports, __webpack_require__) {
  2827. "use strict";
  2828. Object.defineProperty(exports, "__esModule", {
  2829. value: true
  2830. });
  2831. exports.default = style;
  2832. /**
  2833. * Apply a map of styles to an element
  2834. *
  2835. * @param {HTMLElement} el The element that the styles will be applied to
  2836. * @param {Object} styles The map of propName: attribute, both are used as-is
  2837. *
  2838. * @return {HTMLElement} el
  2839. */
  2840. function style(el, styles) {
  2841. Object.keys(styles).forEach(function (prop) {
  2842. if (el.style[prop] !== styles[prop]) {
  2843. el.style[prop] = styles[prop];
  2844. }
  2845. });
  2846. return el;
  2847. }
  2848. module.exports = exports.default;
  2849. /***/ }),
  2850. /***/ "./src/wavesurfer.js":
  2851. /*!***************************!*\
  2852. !*** ./src/wavesurfer.js ***!
  2853. \***************************/
  2854. /*! no static exports found */
  2855. /***/ (function(module, exports, __webpack_require__) {
  2856. "use strict";
  2857. Object.defineProperty(exports, "__esModule", {
  2858. value: true
  2859. });
  2860. exports.default = void 0;
  2861. var util = _interopRequireWildcard(__webpack_require__(/*! ./util */ "./src/util/index.js"));
  2862. var _drawer = _interopRequireDefault(__webpack_require__(/*! ./drawer.multicanvas */ "./src/drawer.multicanvas.js"));
  2863. var _webaudio = _interopRequireDefault(__webpack_require__(/*! ./webaudio */ "./src/webaudio.js"));
  2864. var _mediaelement = _interopRequireDefault(__webpack_require__(/*! ./mediaelement */ "./src/mediaelement.js"));
  2865. var _peakcache = _interopRequireDefault(__webpack_require__(/*! ./peakcache */ "./src/peakcache.js"));
  2866. var _mediaelementWebaudio = _interopRequireDefault(__webpack_require__(/*! ./mediaelement-webaudio */ "./src/mediaelement-webaudio.js"));
  2867. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  2868. function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; }
  2869. function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
  2870. function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
  2871. function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
  2872. function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
  2873. function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
  2874. function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
  2875. function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
  2876. function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
  2877. function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
  2878. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  2879. function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
  2880. function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
  2881. /*
  2882. * This work is licensed under a BSD-3-Clause License.
  2883. */
  2884. /** @external {HTMLElement} https://developer.mozilla.org/en/docs/Web/API/HTMLElement */
  2885. /** @external {OfflineAudioContext} https://developer.mozilla.org/en-US/docs/Web/API/OfflineAudioContext */
  2886. /** @external {File} https://developer.mozilla.org/en-US/docs/Web/API/File */
  2887. /** @external {Blob} https://developer.mozilla.org/en-US/docs/Web/API/Blob */
  2888. /** @external {CanvasRenderingContext2D} https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D */
  2889. /** @external {MediaStreamConstraints} https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamConstraints */
  2890. /** @external {AudioNode} https://developer.mozilla.org/de/docs/Web/API/AudioNode */
  2891. /**
  2892. * @typedef {Object} WavesurferParams
  2893. * @property {AudioContext} audioContext=null Use your own previously
  2894. * initialized AudioContext or leave blank.
  2895. * @property {number} audioRate=1 Speed at which to play audio. Lower number is
  2896. * slower.
  2897. * @property {ScriptProcessorNode} audioScriptProcessor=null Use your own previously
  2898. * initialized ScriptProcessorNode or leave blank.
  2899. * @property {boolean} autoCenter=true If a scrollbar is present, center the
  2900. * waveform on current progress
  2901. * @property {number} autoCenterRate=5 If autoCenter is active, rate at which the
  2902. * waveform is centered
  2903. * @property {boolean} autoCenterImmediately=false If autoCenter is active, immediately
  2904. * center waveform on current progress
  2905. * @property {string} backend='WebAudio' `'WebAudio'|'MediaElement'|'MediaElementWebAudio'` In most cases
  2906. * you don't have to set this manually. MediaElement is a fallback for unsupported browsers.
  2907. * MediaElementWebAudio allows to use WebAudio API also with big audio files, loading audio like with
  2908. * MediaElement backend (HTML5 audio tag). You have to use the same methods of MediaElement backend for loading and
  2909. * playback, giving also peaks, so the audio data are not decoded. In this way you can use WebAudio features, like filters,
  2910. * also with audio with big duration. For example:
  2911. * ` wavesurfer.load(url | HTMLMediaElement, peaks, preload, duration);
  2912. * wavesurfer.play();
  2913. * wavesurfer.setFilter(customFilter);
  2914. * `
  2915. * @property {string} backgroundColor=null Change background color of the
  2916. * waveform container.
  2917. * @property {number} barHeight=1 The height of the wave bars.
  2918. * @property {number} barRadius=0 The radius of the wave bars. Makes bars rounded
  2919. * @property {number} barGap=null The optional spacing between bars of the wave,
  2920. * if not provided will be calculated in legacy format.
  2921. * @property {number} barWidth=null Draw the waveform using bars.
  2922. * @property {number} barMinHeight=null If specified, draw at least a bar of this height,
  2923. * eliminating waveform gaps
  2924. * @property {boolean} closeAudioContext=false Close and nullify all audio
  2925. * contexts when the destroy method is called.
  2926. * @property {!string|HTMLElement} container CSS selector or HTML element where
  2927. * the waveform should be drawn. This is the only required parameter.
  2928. * @property {string} cursorColor='#333' The fill color of the cursor indicating
  2929. * the playhead position.
  2930. * @property {number} cursorWidth=1 Measured in pixels.
  2931. * @property {object} drawingContextAttributes={desynchronized: false} Drawing context
  2932. * attributes.
  2933. * @property {number} duration=null Optional audio length so pre-rendered peaks
  2934. * can be display immediately for example.
  2935. * @property {boolean} fillParent=true Whether to fill the entire container or
  2936. * draw only according to `minPxPerSec`.
  2937. * @property {boolean} forceDecode=false Force decoding of audio using web audio
  2938. * when zooming to get a more detailed waveform.
  2939. * @property {number} height=128 The height of the waveform. Measured in
  2940. * pixels.
  2941. * @property {boolean} hideScrollbar=false Whether to hide the horizontal
  2942. * scrollbar when one would normally be shown.
  2943. * @property {boolean} interact=true Whether the mouse interaction will be
  2944. * enabled at initialization. You can switch this parameter at any time later
  2945. * on.
  2946. * @property {boolean} loopSelection=true (Use with regions plugin) Enable
  2947. * looping of selected regions
  2948. * @property {number} maxCanvasWidth=4000 Maximum width of a single canvas in
  2949. * pixels, excluding a small overlap (2 * `pixelRatio`, rounded up to the next
  2950. * even integer). If the waveform is longer than this value, additional canvases
  2951. * will be used to render the waveform, which is useful for very large waveforms
  2952. * that may be too wide for browsers to draw on a single canvas.
  2953. * @property {boolean} mediaControls=false (Use with backend `MediaElement` or `MediaElementWebAudio`)
  2954. * this enables the native controls for the media element
  2955. * @property {string} mediaType='audio' (Use with backend `MediaElement` or `MediaElementWebAudio`)
  2956. * `'audio'|'video'` ('video' only for `MediaElement`)
  2957. * @property {number} minPxPerSec=20 Minimum number of pixels per second of
  2958. * audio.
  2959. * @property {boolean} normalize=false If true, normalize by the maximum peak
  2960. * instead of 1.0.
  2961. * @property {boolean} partialRender=false Use the PeakCache to improve
  2962. * rendering speed of large waveforms
  2963. * @property {number} pixelRatio=window.devicePixelRatio The pixel ratio used to
  2964. * calculate display
  2965. * @property {PluginDefinition[]} plugins=[] An array of plugin definitions to
  2966. * register during instantiation, they will be directly initialised unless they
  2967. * are added with the `deferInit` property set to true.
  2968. * @property {string} progressColor='#555' The fill color of the part of the
  2969. * waveform behind the cursor. When `progressColor` and `waveColor` are the same
  2970. * the progress wave is not rendered at all.
  2971. * @property {boolean} removeMediaElementOnDestroy=true Set to false to keep the
  2972. * media element in the DOM when the player is destroyed. This is useful when
  2973. * reusing an existing media element via the `loadMediaElement` method.
  2974. * @property {Object} renderer=MultiCanvas Can be used to inject a custom
  2975. * renderer.
  2976. * @property {boolean|number} responsive=false If set to `true` resize the
  2977. * waveform, when the window is resized. This is debounced with a `100ms`
  2978. * timeout by default. If this parameter is a number it represents that timeout.
  2979. * @property {boolean} rtl=false If set to `true`, renders waveform from
  2980. * right-to-left.
  2981. * @property {boolean} scrollParent=false Whether to scroll the container with a
  2982. * lengthy waveform. Otherwise the waveform is shrunk to the container width
  2983. * (see fillParent).
  2984. * @property {number} skipLength=2 Number of seconds to skip with the
  2985. * skipForward() and skipBackward() methods.
  2986. * @property {boolean} splitChannels=false Render with separate waveforms for
  2987. * the channels of the audio
  2988. * @property {string} waveColor='#999' The fill color of the waveform after the
  2989. * cursor.
  2990. * @property {object} xhr={} XHR options. For example:
  2991. * `let xhr = {
  2992. * cache: 'default',
  2993. * mode: 'cors',
  2994. * method: 'GET',
  2995. * credentials: 'same-origin',
  2996. * redirect: 'follow',
  2997. * referrer: 'client',
  2998. * requestHeaders: [
  2999. * {
  3000. * key: 'Authorization',
  3001. * value: 'my-token'
  3002. * }
  3003. * ]
  3004. * };`
  3005. */
  3006. /**
  3007. * @typedef {Object} PluginDefinition
  3008. * @desc The Object used to describe a plugin
  3009. * @example wavesurfer.addPlugin(pluginDefinition);
  3010. * @property {string} name The name of the plugin, the plugin instance will be
  3011. * added as a property to the wavesurfer instance under this name
  3012. * @property {?Object} staticProps The properties that should be added to the
  3013. * wavesurfer instance as static properties
  3014. * @property {?boolean} deferInit Don't initialise plugin
  3015. * automatically
  3016. * @property {Object} params={} The plugin parameters, they are the first parameter
  3017. * passed to the plugin class constructor function
  3018. * @property {PluginClass} instance The plugin instance factory, is called with
  3019. * the dependency specified in extends. Returns the plugin class.
  3020. */
  3021. /**
  3022. * @interface PluginClass
  3023. *
  3024. * @desc This is the interface which is implemented by all plugin classes. Note
  3025. * that this only turns into an observer after being passed through
  3026. * `wavesurfer.addPlugin`.
  3027. *
  3028. * @extends {Observer}
  3029. */
  3030. var PluginClass = /*#__PURE__*/function () {
  3031. _createClass(PluginClass, [{
  3032. key: "create",
  3033. /**
  3034. * Plugin definition factory
  3035. *
  3036. * This function must be used to create a plugin definition which can be
  3037. * used by wavesurfer to correctly instantiate the plugin.
  3038. *
  3039. * It returns a `PluginDefinition` object representing the plugin.
  3040. *
  3041. * @param {Object} params={} The plugin params (specific to the plugin)
  3042. */
  3043. value: function create(params) {}
  3044. /**
  3045. * Construct the plugin
  3046. *
  3047. * @param {Object} params={} The plugin params (specific to the plugin)
  3048. * @param {Object} ws The wavesurfer instance
  3049. */
  3050. }]);
  3051. function PluginClass(params, ws) {
  3052. _classCallCheck(this, PluginClass);
  3053. }
  3054. /**
  3055. * Initialise the plugin
  3056. *
  3057. * Start doing something. This is called by
  3058. * `wavesurfer.initPlugin(pluginName)`
  3059. */
  3060. _createClass(PluginClass, [{
  3061. key: "init",
  3062. value: function init() {}
  3063. /**
  3064. * Destroy the plugin instance
  3065. *
  3066. * Stop doing something. This is called by
  3067. * `wavesurfer.destroyPlugin(pluginName)`
  3068. */
  3069. }, {
  3070. key: "destroy",
  3071. value: function destroy() {}
  3072. }]);
  3073. return PluginClass;
  3074. }();
  3075. /**
  3076. * WaveSurfer core library class
  3077. *
  3078. * @extends {Observer}
  3079. * @example
  3080. * const params = {
  3081. * container: '#waveform',
  3082. * waveColor: 'violet',
  3083. * progressColor: 'purple'
  3084. * };
  3085. *
  3086. * // initialise like this
  3087. * const wavesurfer = WaveSurfer.create(params);
  3088. *
  3089. * // or like this ...
  3090. * const wavesurfer = new WaveSurfer(params);
  3091. * wavesurfer.init();
  3092. *
  3093. * // load audio file
  3094. * wavesurfer.load('example/media/demo.wav');
  3095. */
  3096. var WaveSurfer = /*#__PURE__*/function (_util$Observer) {
  3097. _inherits(WaveSurfer, _util$Observer);
  3098. var _super = _createSuper(WaveSurfer);
  3099. _createClass(WaveSurfer, null, [{
  3100. key: "create",
  3101. /** @private */
  3102. /** @private */
  3103. /**
  3104. * Instantiate this class, call its `init` function and returns it
  3105. *
  3106. * @param {WavesurferParams} params The wavesurfer parameters
  3107. * @return {Object} WaveSurfer instance
  3108. * @example const wavesurfer = WaveSurfer.create(params);
  3109. */
  3110. value: function create(params) {
  3111. var wavesurfer = new WaveSurfer(params);
  3112. return wavesurfer.init();
  3113. }
  3114. /**
  3115. * The library version number is available as a static property of the
  3116. * WaveSurfer class
  3117. *
  3118. * @type {String}
  3119. * @example
  3120. * console.log('Using wavesurfer.js ' + WaveSurfer.VERSION);
  3121. */
  3122. }]);
  3123. /**
  3124. * Initialise wavesurfer instance
  3125. *
  3126. * @param {WavesurferParams} params Instantiation options for wavesurfer
  3127. * @example
  3128. * const wavesurfer = new WaveSurfer(params);
  3129. * @returns {this} Wavesurfer instance
  3130. */
  3131. function WaveSurfer(params) {
  3132. var _this;
  3133. _classCallCheck(this, WaveSurfer);
  3134. _this = _super.call(this);
  3135. /**
  3136. * Extract relevant parameters (or defaults)
  3137. * @private
  3138. */
  3139. _this.defaultParams = {
  3140. audioContext: null,
  3141. audioScriptProcessor: null,
  3142. audioRate: 1,
  3143. autoCenter: true,
  3144. autoCenterRate: 5,
  3145. autoCenterImmediately: false,
  3146. backend: 'WebAudio',
  3147. backgroundColor: null,
  3148. barHeight: 1,
  3149. barRadius: 0,
  3150. barGap: null,
  3151. barMinHeight: null,
  3152. container: null,
  3153. cursorColor: '#333',
  3154. cursorWidth: 1,
  3155. dragSelection: true,
  3156. drawingContextAttributes: {
  3157. // Boolean that hints the user agent to reduce the latency
  3158. // by desynchronizing the canvas paint cycle from the event
  3159. // loop
  3160. desynchronized: false
  3161. },
  3162. duration: null,
  3163. fillParent: true,
  3164. forceDecode: false,
  3165. height: 128,
  3166. hideScrollbar: false,
  3167. interact: true,
  3168. loopSelection: true,
  3169. maxCanvasWidth: 4000,
  3170. mediaContainer: null,
  3171. mediaControls: false,
  3172. mediaType: 'audio',
  3173. minPxPerSec: 20,
  3174. normalize: false,
  3175. partialRender: false,
  3176. pixelRatio: window.devicePixelRatio || screen.deviceXDPI / screen.logicalXDPI,
  3177. plugins: [],
  3178. progressColor: '#555',
  3179. removeMediaElementOnDestroy: true,
  3180. renderer: _drawer.default,
  3181. responsive: false,
  3182. rtl: false,
  3183. scrollParent: false,
  3184. skipLength: 2,
  3185. splitChannels: false,
  3186. splitChannelsOptions: {
  3187. overlay: false,
  3188. channelColors: {},
  3189. filterChannels: []
  3190. },
  3191. waveColor: '#999',
  3192. xhr: {}
  3193. };
  3194. _this.backends = {
  3195. MediaElement: _mediaelement.default,
  3196. WebAudio: _webaudio.default,
  3197. MediaElementWebAudio: _mediaelementWebaudio.default
  3198. };
  3199. _this.util = util;
  3200. _this.params = Object.assign({}, _this.defaultParams, params);
  3201. /** @private */
  3202. _this.container = 'string' == typeof params.container ? document.querySelector(_this.params.container) : _this.params.container;
  3203. if (!_this.container) {
  3204. throw new Error('Container element not found');
  3205. }
  3206. if (_this.params.mediaContainer == null) {
  3207. /** @private */
  3208. _this.mediaContainer = _this.container;
  3209. } else if (typeof _this.params.mediaContainer == 'string') {
  3210. /** @private */
  3211. _this.mediaContainer = document.querySelector(_this.params.mediaContainer);
  3212. } else {
  3213. /** @private */
  3214. _this.mediaContainer = _this.params.mediaContainer;
  3215. }
  3216. if (!_this.mediaContainer) {
  3217. throw new Error('Media Container element not found');
  3218. }
  3219. if (_this.params.maxCanvasWidth <= 1) {
  3220. throw new Error('maxCanvasWidth must be greater than 1');
  3221. } else if (_this.params.maxCanvasWidth % 2 == 1) {
  3222. throw new Error('maxCanvasWidth must be an even number');
  3223. }
  3224. if (_this.params.rtl === true) {
  3225. util.style(_this.container, {
  3226. transform: 'rotateY(180deg)'
  3227. });
  3228. }
  3229. if (_this.params.backgroundColor) {
  3230. _this.setBackgroundColor(_this.params.backgroundColor);
  3231. }
  3232. /**
  3233. * @private Used to save the current volume when muting so we can
  3234. * restore once unmuted
  3235. * @type {number}
  3236. */
  3237. _this.savedVolume = 0;
  3238. /**
  3239. * @private The current muted state
  3240. * @type {boolean}
  3241. */
  3242. _this.isMuted = false;
  3243. /**
  3244. * @private Will hold a list of event descriptors that need to be
  3245. * canceled on subsequent loads of audio
  3246. * @type {Object[]}
  3247. */
  3248. _this.tmpEvents = [];
  3249. /**
  3250. * @private Holds any running audio downloads
  3251. * @type {Observer}
  3252. */
  3253. _this.currentRequest = null;
  3254. /** @private */
  3255. _this.arraybuffer = null;
  3256. /** @private */
  3257. _this.drawer = null;
  3258. /** @private */
  3259. _this.backend = null;
  3260. /** @private */
  3261. _this.peakCache = null; // cache constructor objects
  3262. if (typeof _this.params.renderer !== 'function') {
  3263. throw new Error('Renderer parameter is invalid');
  3264. }
  3265. /**
  3266. * @private The uninitialised Drawer class
  3267. */
  3268. _this.Drawer = _this.params.renderer;
  3269. /**
  3270. * @private The uninitialised Backend class
  3271. */
  3272. // Back compat
  3273. if (_this.params.backend == 'AudioElement') {
  3274. _this.params.backend = 'MediaElement';
  3275. }
  3276. if ((_this.params.backend == 'WebAudio' || _this.params.backend === 'MediaElementWebAudio') && !_webaudio.default.prototype.supportsWebAudio.call(null)) {
  3277. _this.params.backend = 'MediaElement';
  3278. }
  3279. _this.Backend = _this.backends[_this.params.backend];
  3280. /**
  3281. * @private map of plugin names that are currently initialised
  3282. */
  3283. _this.initialisedPluginList = {};
  3284. /** @private */
  3285. _this.isDestroyed = false;
  3286. /**
  3287. * Get the current ready status.
  3288. *
  3289. * @example const isReady = wavesurfer.isReady;
  3290. * @return {boolean}
  3291. */
  3292. _this.isReady = false; // responsive debounced event listener. If this.params.responsive is not
  3293. // set, this is never called. Use 100ms or this.params.responsive as
  3294. // timeout for the debounce function.
  3295. var prevWidth = 0;
  3296. _this._onResize = util.debounce(function () {
  3297. if (prevWidth != _this.drawer.wrapper.clientWidth && !_this.params.scrollParent) {
  3298. prevWidth = _this.drawer.wrapper.clientWidth;
  3299. _this.drawer.fireEvent('redraw');
  3300. }
  3301. }, typeof _this.params.responsive === 'number' ? _this.params.responsive : 100);
  3302. return _possibleConstructorReturn(_this, _assertThisInitialized(_this));
  3303. }
  3304. /**
  3305. * Initialise the wave
  3306. *
  3307. * @example
  3308. * var wavesurfer = new WaveSurfer(params);
  3309. * wavesurfer.init();
  3310. * @return {this} The wavesurfer instance
  3311. */
  3312. _createClass(WaveSurfer, [{
  3313. key: "init",
  3314. value: function init() {
  3315. this.registerPlugins(this.params.plugins);
  3316. this.createDrawer();
  3317. this.createBackend();
  3318. this.createPeakCache();
  3319. return this;
  3320. }
  3321. /**
  3322. * Add and initialise array of plugins (if `plugin.deferInit` is falsey),
  3323. * this function is called in the init function of wavesurfer
  3324. *
  3325. * @param {PluginDefinition[]} plugins An array of plugin definitions
  3326. * @emits {WaveSurfer#plugins-registered} Called with the array of plugin definitions
  3327. * @return {this} The wavesurfer instance
  3328. */
  3329. }, {
  3330. key: "registerPlugins",
  3331. value: function registerPlugins(plugins) {
  3332. var _this2 = this;
  3333. // first instantiate all the plugins
  3334. plugins.forEach(function (plugin) {
  3335. return _this2.addPlugin(plugin);
  3336. }); // now run the init functions
  3337. plugins.forEach(function (plugin) {
  3338. // call init function of the plugin if deferInit is falsey
  3339. // in that case you would manually use initPlugins()
  3340. if (!plugin.deferInit) {
  3341. _this2.initPlugin(plugin.name);
  3342. }
  3343. });
  3344. this.fireEvent('plugins-registered', plugins);
  3345. return this;
  3346. }
  3347. /**
  3348. * Get a map of plugin names that are currently initialised
  3349. *
  3350. * @example wavesurfer.getPlugins();
  3351. * @return {Object} Object with plugin names
  3352. */
  3353. }, {
  3354. key: "getActivePlugins",
  3355. value: function getActivePlugins() {
  3356. return this.initialisedPluginList;
  3357. }
  3358. /**
  3359. * Add a plugin object to wavesurfer
  3360. *
  3361. * @param {PluginDefinition} plugin A plugin definition
  3362. * @emits {WaveSurfer#plugin-added} Called with the name of the plugin that was added
  3363. * @example wavesurfer.addPlugin(WaveSurfer.minimap());
  3364. * @return {this} The wavesurfer instance
  3365. */
  3366. }, {
  3367. key: "addPlugin",
  3368. value: function addPlugin(plugin) {
  3369. var _this3 = this;
  3370. if (!plugin.name) {
  3371. throw new Error('Plugin does not have a name!');
  3372. }
  3373. if (!plugin.instance) {
  3374. throw new Error("Plugin ".concat(plugin.name, " does not have an instance property!"));
  3375. } // staticProps properties are applied to wavesurfer instance
  3376. if (plugin.staticProps) {
  3377. Object.keys(plugin.staticProps).forEach(function (pluginStaticProp) {
  3378. /**
  3379. * Properties defined in a plugin definition's `staticProps` property are added as
  3380. * staticProps properties of the WaveSurfer instance
  3381. */
  3382. _this3[pluginStaticProp] = plugin.staticProps[pluginStaticProp];
  3383. });
  3384. }
  3385. var Instance = plugin.instance; // turn the plugin instance into an observer
  3386. var observerPrototypeKeys = Object.getOwnPropertyNames(util.Observer.prototype);
  3387. observerPrototypeKeys.forEach(function (key) {
  3388. Instance.prototype[key] = util.Observer.prototype[key];
  3389. });
  3390. /**
  3391. * Instantiated plugin classes are added as a property of the wavesurfer
  3392. * instance
  3393. * @type {Object}
  3394. */
  3395. this[plugin.name] = new Instance(plugin.params || {}, this);
  3396. this.fireEvent('plugin-added', plugin.name);
  3397. return this;
  3398. }
  3399. /**
  3400. * Initialise a plugin
  3401. *
  3402. * @param {string} name A plugin name
  3403. * @emits WaveSurfer#plugin-initialised
  3404. * @example wavesurfer.initPlugin('minimap');
  3405. * @return {this} The wavesurfer instance
  3406. */
  3407. }, {
  3408. key: "initPlugin",
  3409. value: function initPlugin(name) {
  3410. if (!this[name]) {
  3411. throw new Error("Plugin ".concat(name, " has not been added yet!"));
  3412. }
  3413. if (this.initialisedPluginList[name]) {
  3414. // destroy any already initialised plugins
  3415. this.destroyPlugin(name);
  3416. }
  3417. this[name].init();
  3418. this.initialisedPluginList[name] = true;
  3419. this.fireEvent('plugin-initialised', name);
  3420. return this;
  3421. }
  3422. /**
  3423. * Destroy a plugin
  3424. *
  3425. * @param {string} name A plugin name
  3426. * @emits WaveSurfer#plugin-destroyed
  3427. * @example wavesurfer.destroyPlugin('minimap');
  3428. * @returns {this} The wavesurfer instance
  3429. */
  3430. }, {
  3431. key: "destroyPlugin",
  3432. value: function destroyPlugin(name) {
  3433. if (!this[name]) {
  3434. throw new Error("Plugin ".concat(name, " has not been added yet and cannot be destroyed!"));
  3435. }
  3436. if (!this.initialisedPluginList[name]) {
  3437. throw new Error("Plugin ".concat(name, " is not active and cannot be destroyed!"));
  3438. }
  3439. if (typeof this[name].destroy !== 'function') {
  3440. throw new Error("Plugin ".concat(name, " does not have a destroy function!"));
  3441. }
  3442. this[name].destroy();
  3443. delete this.initialisedPluginList[name];
  3444. this.fireEvent('plugin-destroyed', name);
  3445. return this;
  3446. }
  3447. /**
  3448. * Destroy all initialised plugins. Convenience function to use when
  3449. * wavesurfer is removed
  3450. *
  3451. * @private
  3452. */
  3453. }, {
  3454. key: "destroyAllPlugins",
  3455. value: function destroyAllPlugins() {
  3456. var _this4 = this;
  3457. Object.keys(this.initialisedPluginList).forEach(function (name) {
  3458. return _this4.destroyPlugin(name);
  3459. });
  3460. }
  3461. /**
  3462. * Create the drawer and draw the waveform
  3463. *
  3464. * @private
  3465. * @emits WaveSurfer#drawer-created
  3466. */
  3467. }, {
  3468. key: "createDrawer",
  3469. value: function createDrawer() {
  3470. var _this5 = this;
  3471. this.drawer = new this.Drawer(this.container, this.params);
  3472. this.drawer.init();
  3473. this.fireEvent('drawer-created', this.drawer);
  3474. if (this.params.responsive !== false) {
  3475. window.addEventListener('resize', this._onResize, true);
  3476. window.addEventListener('orientationchange', this._onResize, true);
  3477. }
  3478. this.drawer.on('redraw', function () {
  3479. _this5.drawBuffer();
  3480. _this5.drawer.progress(_this5.backend.getPlayedPercents());
  3481. }); // Click-to-seek
  3482. this.drawer.on('click', function (e, progress) {
  3483. setTimeout(function () {
  3484. return _this5.seekTo(progress);
  3485. }, 0);
  3486. }); // Relay the scroll event from the drawer
  3487. this.drawer.on('scroll', function (e) {
  3488. if (_this5.params.partialRender) {
  3489. _this5.drawBuffer();
  3490. }
  3491. _this5.fireEvent('scroll', e);
  3492. });
  3493. }
  3494. /**
  3495. * Create the backend
  3496. *
  3497. * @private
  3498. * @emits WaveSurfer#backend-created
  3499. */
  3500. }, {
  3501. key: "createBackend",
  3502. value: function createBackend() {
  3503. var _this6 = this;
  3504. if (this.backend) {
  3505. this.backend.destroy();
  3506. }
  3507. this.backend = new this.Backend(this.params);
  3508. this.backend.init();
  3509. this.fireEvent('backend-created', this.backend);
  3510. this.backend.on('finish', function () {
  3511. _this6.drawer.progress(_this6.backend.getPlayedPercents());
  3512. _this6.fireEvent('finish');
  3513. });
  3514. this.backend.on('play', function () {
  3515. return _this6.fireEvent('play');
  3516. });
  3517. this.backend.on('pause', function () {
  3518. return _this6.fireEvent('pause');
  3519. });
  3520. this.backend.on('audioprocess', function (time) {
  3521. _this6.drawer.progress(_this6.backend.getPlayedPercents());
  3522. _this6.fireEvent('audioprocess', time);
  3523. }); // only needed for MediaElement and MediaElementWebAudio backend
  3524. if (this.params.backend === 'MediaElement' || this.params.backend === 'MediaElementWebAudio') {
  3525. this.backend.on('seek', function () {
  3526. _this6.drawer.progress(_this6.backend.getPlayedPercents());
  3527. });
  3528. this.backend.on('volume', function () {
  3529. var newVolume = _this6.getVolume();
  3530. _this6.fireEvent('volume', newVolume);
  3531. if (_this6.backend.isMuted !== _this6.isMuted) {
  3532. _this6.isMuted = _this6.backend.isMuted;
  3533. _this6.fireEvent('mute', _this6.isMuted);
  3534. }
  3535. });
  3536. }
  3537. }
  3538. /**
  3539. * Create the peak cache
  3540. *
  3541. * @private
  3542. */
  3543. }, {
  3544. key: "createPeakCache",
  3545. value: function createPeakCache() {
  3546. if (this.params.partialRender) {
  3547. this.peakCache = new _peakcache.default();
  3548. }
  3549. }
  3550. /**
  3551. * Get the duration of the audio clip
  3552. *
  3553. * @example const duration = wavesurfer.getDuration();
  3554. * @return {number} Duration in seconds
  3555. */
  3556. }, {
  3557. key: "getDuration",
  3558. value: function getDuration() {
  3559. return this.backend.getDuration();
  3560. }
  3561. /**
  3562. * Get the current playback position
  3563. *
  3564. * @example const currentTime = wavesurfer.getCurrentTime();
  3565. * @return {number} Playback position in seconds
  3566. */
  3567. }, {
  3568. key: "getCurrentTime",
  3569. value: function getCurrentTime() {
  3570. return this.backend.getCurrentTime();
  3571. }
  3572. /**
  3573. * Set the current play time in seconds.
  3574. *
  3575. * @param {number} seconds A positive number in seconds. E.g. 10 means 10
  3576. * seconds, 60 means 1 minute
  3577. */
  3578. }, {
  3579. key: "setCurrentTime",
  3580. value: function setCurrentTime(seconds) {
  3581. if (seconds >= this.getDuration()) {
  3582. this.seekTo(1);
  3583. } else {
  3584. this.seekTo(seconds / this.getDuration());
  3585. }
  3586. }
  3587. /**
  3588. * Starts playback from the current position. Optional start and end
  3589. * measured in seconds can be used to set the range of audio to play.
  3590. *
  3591. * @param {?number} start Position to start at
  3592. * @param {?number} end Position to end at
  3593. * @emits WaveSurfer#interaction
  3594. * @return {Promise} Result of the backend play method
  3595. * @example
  3596. * // play from second 1 to 5
  3597. * wavesurfer.play(1, 5);
  3598. */
  3599. }, {
  3600. key: "play",
  3601. value: function play(start, end) {
  3602. var _this7 = this;
  3603. this.fireEvent('interaction', function () {
  3604. return _this7.play(start, end);
  3605. });
  3606. return this.backend.play(start, end);
  3607. }
  3608. /**
  3609. * Set a point in seconds for playback to stop at.
  3610. *
  3611. * @param {number} position Position (in seconds) to stop at
  3612. * @version 3.3.0
  3613. */
  3614. }, {
  3615. key: "setPlayEnd",
  3616. value: function setPlayEnd(position) {
  3617. this.backend.setPlayEnd(position);
  3618. }
  3619. /**
  3620. * Stops and pauses playback
  3621. *
  3622. * @example wavesurfer.pause();
  3623. * @return {Promise} Result of the backend pause method
  3624. */
  3625. }, {
  3626. key: "pause",
  3627. value: function pause() {
  3628. if (!this.backend.isPaused()) {
  3629. return this.backend.pause();
  3630. }
  3631. }
  3632. /**
  3633. * Toggle playback
  3634. *
  3635. * @example wavesurfer.playPause();
  3636. * @return {Promise} Result of the backend play or pause method
  3637. */
  3638. }, {
  3639. key: "playPause",
  3640. value: function playPause() {
  3641. return this.backend.isPaused() ? this.play() : this.pause();
  3642. }
  3643. /**
  3644. * Get the current playback state
  3645. *
  3646. * @example const isPlaying = wavesurfer.isPlaying();
  3647. * @return {boolean} False if paused, true if playing
  3648. */
  3649. }, {
  3650. key: "isPlaying",
  3651. value: function isPlaying() {
  3652. return !this.backend.isPaused();
  3653. }
  3654. /**
  3655. * Skip backward
  3656. *
  3657. * @param {?number} seconds Amount to skip back, if not specified `skipLength`
  3658. * is used
  3659. * @example wavesurfer.skipBackward();
  3660. */
  3661. }, {
  3662. key: "skipBackward",
  3663. value: function skipBackward(seconds) {
  3664. this.skip(-seconds || -this.params.skipLength);
  3665. }
  3666. /**
  3667. * Skip forward
  3668. *
  3669. * @param {?number} seconds Amount to skip back, if not specified `skipLength`
  3670. * is used
  3671. * @example wavesurfer.skipForward();
  3672. */
  3673. }, {
  3674. key: "skipForward",
  3675. value: function skipForward(seconds) {
  3676. this.skip(seconds || this.params.skipLength);
  3677. }
  3678. /**
  3679. * Skip a number of seconds from the current position (use a negative value
  3680. * to go backwards).
  3681. *
  3682. * @param {number} offset Amount to skip back or forwards
  3683. * @example
  3684. * // go back 2 seconds
  3685. * wavesurfer.skip(-2);
  3686. */
  3687. }, {
  3688. key: "skip",
  3689. value: function skip(offset) {
  3690. var duration = this.getDuration() || 1;
  3691. var position = this.getCurrentTime() || 0;
  3692. position = Math.max(0, Math.min(duration, position + (offset || 0)));
  3693. this.seekAndCenter(position / duration);
  3694. }
  3695. /**
  3696. * Seeks to a position and centers the view
  3697. *
  3698. * @param {number} progress Between 0 (=beginning) and 1 (=end)
  3699. * @example
  3700. * // seek and go to the middle of the audio
  3701. * wavesurfer.seekTo(0.5);
  3702. */
  3703. }, {
  3704. key: "seekAndCenter",
  3705. value: function seekAndCenter(progress) {
  3706. this.seekTo(progress);
  3707. this.drawer.recenter(progress);
  3708. }
  3709. /**
  3710. * Seeks to a position
  3711. *
  3712. * @param {number} progress Between 0 (=beginning) and 1 (=end)
  3713. * @emits WaveSurfer#interaction
  3714. * @emits WaveSurfer#seek
  3715. * @example
  3716. * // seek to the middle of the audio
  3717. * wavesurfer.seekTo(0.5);
  3718. */
  3719. }, {
  3720. key: "seekTo",
  3721. value: function seekTo(progress) {
  3722. var _this8 = this;
  3723. // return an error if progress is not a number between 0 and 1
  3724. if (typeof progress !== 'number' || !isFinite(progress) || progress < 0 || progress > 1) {
  3725. throw new Error('Error calling wavesurfer.seekTo, parameter must be a number between 0 and 1!');
  3726. }
  3727. this.fireEvent('interaction', function () {
  3728. return _this8.seekTo(progress);
  3729. });
  3730. var paused = this.backend.isPaused(); // avoid draw wrong position while playing backward seeking
  3731. if (!paused) {
  3732. this.backend.pause();
  3733. } // avoid small scrolls while paused seeking
  3734. var oldScrollParent = this.params.scrollParent;
  3735. this.params.scrollParent = false;
  3736. this.backend.seekTo(progress * this.getDuration());
  3737. this.drawer.progress(progress);
  3738. if (!paused) {
  3739. this.backend.play();
  3740. }
  3741. this.params.scrollParent = oldScrollParent;
  3742. this.fireEvent('seek', progress);
  3743. }
  3744. /**
  3745. * Stops and goes to the beginning.
  3746. *
  3747. * @example wavesurfer.stop();
  3748. */
  3749. }, {
  3750. key: "stop",
  3751. value: function stop() {
  3752. this.pause();
  3753. this.seekTo(0);
  3754. this.drawer.progress(0);
  3755. }
  3756. /**
  3757. * Sets the ID of the audio device to use for output and returns a Promise.
  3758. *
  3759. * @param {string} deviceId String value representing underlying output
  3760. * device
  3761. * @returns {Promise} `Promise` that resolves to `undefined` when there are
  3762. * no errors detected.
  3763. */
  3764. }, {
  3765. key: "setSinkId",
  3766. value: function setSinkId(deviceId) {
  3767. return this.backend.setSinkId(deviceId);
  3768. }
  3769. /**
  3770. * Set the playback volume.
  3771. *
  3772. * @param {number} newVolume A value between 0 and 1, 0 being no
  3773. * volume and 1 being full volume.
  3774. * @emits WaveSurfer#volume
  3775. */
  3776. }, {
  3777. key: "setVolume",
  3778. value: function setVolume(newVolume) {
  3779. this.backend.setVolume(newVolume);
  3780. this.fireEvent('volume', newVolume);
  3781. }
  3782. /**
  3783. * Get the playback volume.
  3784. *
  3785. * @return {number} A value between 0 and 1, 0 being no
  3786. * volume and 1 being full volume.
  3787. */
  3788. }, {
  3789. key: "getVolume",
  3790. value: function getVolume() {
  3791. return this.backend.getVolume();
  3792. }
  3793. /**
  3794. * Set the playback rate.
  3795. *
  3796. * @param {number} rate A positive number. E.g. 0.5 means half the normal
  3797. * speed, 2 means double speed and so on.
  3798. * @example wavesurfer.setPlaybackRate(2);
  3799. */
  3800. }, {
  3801. key: "setPlaybackRate",
  3802. value: function setPlaybackRate(rate) {
  3803. this.backend.setPlaybackRate(rate);
  3804. }
  3805. /**
  3806. * Get the playback rate.
  3807. *
  3808. * @return {number} The current playback rate.
  3809. */
  3810. }, {
  3811. key: "getPlaybackRate",
  3812. value: function getPlaybackRate() {
  3813. return this.backend.getPlaybackRate();
  3814. }
  3815. /**
  3816. * Toggle the volume on and off. If not currently muted it will save the
  3817. * current volume value and turn the volume off. If currently muted then it
  3818. * will restore the volume to the saved value, and then rest the saved
  3819. * value.
  3820. *
  3821. * @example wavesurfer.toggleMute();
  3822. */
  3823. }, {
  3824. key: "toggleMute",
  3825. value: function toggleMute() {
  3826. this.setMute(!this.isMuted);
  3827. }
  3828. /**
  3829. * Enable or disable muted audio
  3830. *
  3831. * @param {boolean} mute Specify `true` to mute audio.
  3832. * @emits WaveSurfer#volume
  3833. * @emits WaveSurfer#mute
  3834. * @example
  3835. * // unmute
  3836. * wavesurfer.setMute(false);
  3837. * console.log(wavesurfer.getMute()) // logs false
  3838. */
  3839. }, {
  3840. key: "setMute",
  3841. value: function setMute(mute) {
  3842. // ignore all muting requests if the audio is already in that state
  3843. if (mute === this.isMuted) {
  3844. this.fireEvent('mute', this.isMuted);
  3845. return;
  3846. }
  3847. if (this.backend.setMute) {
  3848. // Backends such as the MediaElement backend have their own handling
  3849. // of mute, let them handle it.
  3850. this.backend.setMute(mute);
  3851. this.isMuted = mute;
  3852. } else {
  3853. if (mute) {
  3854. // If currently not muted then save current volume,
  3855. // turn off the volume and update the mute properties
  3856. this.savedVolume = this.backend.getVolume();
  3857. this.backend.setVolume(0);
  3858. this.isMuted = true;
  3859. this.fireEvent('volume', 0);
  3860. } else {
  3861. // If currently muted then restore to the saved volume
  3862. // and update the mute properties
  3863. this.backend.setVolume(this.savedVolume);
  3864. this.isMuted = false;
  3865. this.fireEvent('volume', this.savedVolume);
  3866. }
  3867. }
  3868. this.fireEvent('mute', this.isMuted);
  3869. }
  3870. /**
  3871. * Get the current mute status.
  3872. *
  3873. * @example const isMuted = wavesurfer.getMute();
  3874. * @return {boolean} Current mute status
  3875. */
  3876. }, {
  3877. key: "getMute",
  3878. value: function getMute() {
  3879. return this.isMuted;
  3880. }
  3881. /**
  3882. * Get the list of current set filters as an array.
  3883. *
  3884. * Filters must be set with setFilters method first
  3885. *
  3886. * @return {array} List of enabled filters
  3887. */
  3888. }, {
  3889. key: "getFilters",
  3890. value: function getFilters() {
  3891. return this.backend.filters || [];
  3892. }
  3893. /**
  3894. * Toggles `scrollParent` and redraws
  3895. *
  3896. * @example wavesurfer.toggleScroll();
  3897. */
  3898. }, {
  3899. key: "toggleScroll",
  3900. value: function toggleScroll() {
  3901. this.params.scrollParent = !this.params.scrollParent;
  3902. this.drawBuffer();
  3903. }
  3904. /**
  3905. * Toggle mouse interaction
  3906. *
  3907. * @example wavesurfer.toggleInteraction();
  3908. */
  3909. }, {
  3910. key: "toggleInteraction",
  3911. value: function toggleInteraction() {
  3912. this.params.interact = !this.params.interact;
  3913. }
  3914. /**
  3915. * Get the fill color of the waveform after the cursor.
  3916. *
  3917. * @return {string} A CSS color string.
  3918. */
  3919. }, {
  3920. key: "getWaveColor",
  3921. value: function getWaveColor() {
  3922. return this.params.waveColor;
  3923. }
  3924. /**
  3925. * Set the fill color of the waveform after the cursor.
  3926. *
  3927. * @param {string} color A CSS color string.
  3928. * @example wavesurfer.setWaveColor('#ddd');
  3929. */
  3930. }, {
  3931. key: "setWaveColor",
  3932. value: function setWaveColor(color) {
  3933. this.params.waveColor = color;
  3934. this.drawBuffer();
  3935. }
  3936. /**
  3937. * Get the fill color of the waveform behind the cursor.
  3938. *
  3939. * @return {string} A CSS color string.
  3940. */
  3941. }, {
  3942. key: "getProgressColor",
  3943. value: function getProgressColor() {
  3944. return this.params.progressColor;
  3945. }
  3946. /**
  3947. * Set the fill color of the waveform behind the cursor.
  3948. *
  3949. * @param {string} color A CSS color string.
  3950. * @example wavesurfer.setProgressColor('#400');
  3951. */
  3952. }, {
  3953. key: "setProgressColor",
  3954. value: function setProgressColor(color) {
  3955. this.params.progressColor = color;
  3956. this.drawBuffer();
  3957. }
  3958. /**
  3959. * Get the background color of the waveform container.
  3960. *
  3961. * @return {string} A CSS color string.
  3962. */
  3963. }, {
  3964. key: "getBackgroundColor",
  3965. value: function getBackgroundColor() {
  3966. return this.params.backgroundColor;
  3967. }
  3968. /**
  3969. * Set the background color of the waveform container.
  3970. *
  3971. * @param {string} color A CSS color string.
  3972. * @example wavesurfer.setBackgroundColor('#FF00FF');
  3973. */
  3974. }, {
  3975. key: "setBackgroundColor",
  3976. value: function setBackgroundColor(color) {
  3977. this.params.backgroundColor = color;
  3978. util.style(this.container, {
  3979. background: this.params.backgroundColor
  3980. });
  3981. }
  3982. /**
  3983. * Get the fill color of the cursor indicating the playhead
  3984. * position.
  3985. *
  3986. * @return {string} A CSS color string.
  3987. */
  3988. }, {
  3989. key: "getCursorColor",
  3990. value: function getCursorColor() {
  3991. return this.params.cursorColor;
  3992. }
  3993. /**
  3994. * Set the fill color of the cursor indicating the playhead
  3995. * position.
  3996. *
  3997. * @param {string} color A CSS color string.
  3998. * @example wavesurfer.setCursorColor('#222');
  3999. */
  4000. }, {
  4001. key: "setCursorColor",
  4002. value: function setCursorColor(color) {
  4003. this.params.cursorColor = color;
  4004. this.drawer.updateCursor();
  4005. }
  4006. /**
  4007. * Get the height of the waveform.
  4008. *
  4009. * @return {number} Height measured in pixels.
  4010. */
  4011. }, {
  4012. key: "getHeight",
  4013. value: function getHeight() {
  4014. return this.params.height;
  4015. }
  4016. /**
  4017. * Set the height of the waveform.
  4018. *
  4019. * @param {number} height Height measured in pixels.
  4020. * @example wavesurfer.setHeight(200);
  4021. */
  4022. }, {
  4023. key: "setHeight",
  4024. value: function setHeight(height) {
  4025. this.params.height = height;
  4026. this.drawer.setHeight(height * this.params.pixelRatio);
  4027. this.drawBuffer();
  4028. }
  4029. /**
  4030. * Hide channels from being drawn on the waveform if splitting channels.
  4031. *
  4032. * For example, if we want to draw only the peaks for the right stereo channel:
  4033. *
  4034. * const wavesurfer = new WaveSurfer.create({...splitChannels: true});
  4035. * wavesurfer.load('stereo_audio.mp3');
  4036. *
  4037. * wavesurfer.setFilteredChannel([0]); <-- hide left channel peaks.
  4038. *
  4039. * @param {array} channelIndices Channels to be filtered out from drawing.
  4040. * @version 4.0.0
  4041. */
  4042. }, {
  4043. key: "setFilteredChannels",
  4044. value: function setFilteredChannels(channelIndices) {
  4045. this.params.splitChannelsOptions.filterChannels = channelIndices;
  4046. this.drawBuffer();
  4047. }
  4048. /**
  4049. * Get the correct peaks for current wave view-port and render wave
  4050. *
  4051. * @private
  4052. * @emits WaveSurfer#redraw
  4053. */
  4054. }, {
  4055. key: "drawBuffer",
  4056. value: function drawBuffer() {
  4057. var nominalWidth = Math.round(this.getDuration() * this.params.minPxPerSec * this.params.pixelRatio);
  4058. var parentWidth = this.drawer.getWidth();
  4059. var width = nominalWidth; // always start at 0 after zooming for scrolling : issue redraw left part
  4060. var start = 0;
  4061. var end = Math.max(start + parentWidth, width); // Fill container
  4062. if (this.params.fillParent && (!this.params.scrollParent || nominalWidth < parentWidth)) {
  4063. width = parentWidth;
  4064. start = 0;
  4065. end = width;
  4066. }
  4067. var peaks;
  4068. if (this.params.partialRender) {
  4069. var newRanges = this.peakCache.addRangeToPeakCache(width, start, end);
  4070. var i;
  4071. for (i = 0; i < newRanges.length; i++) {
  4072. peaks = this.backend.getPeaks(width, newRanges[i][0], newRanges[i][1]);
  4073. this.drawer.drawPeaks(peaks, width, newRanges[i][0], newRanges[i][1]);
  4074. }
  4075. } else {
  4076. peaks = this.backend.getPeaks(width, start, end);
  4077. this.drawer.drawPeaks(peaks, width, start, end);
  4078. }
  4079. this.fireEvent('redraw', peaks, width);
  4080. }
  4081. /**
  4082. * Horizontally zooms the waveform in and out. It also changes the parameter
  4083. * `minPxPerSec` and enables the `scrollParent` option. Calling the function
  4084. * with a falsey parameter will reset the zoom state.
  4085. *
  4086. * @param {?number} pxPerSec Number of horizontal pixels per second of
  4087. * audio, if none is set the waveform returns to unzoomed state
  4088. * @emits WaveSurfer#zoom
  4089. * @example wavesurfer.zoom(20);
  4090. */
  4091. }, {
  4092. key: "zoom",
  4093. value: function zoom(pxPerSec) {
  4094. if (!pxPerSec) {
  4095. this.params.minPxPerSec = this.defaultParams.minPxPerSec;
  4096. this.params.scrollParent = false;
  4097. } else {
  4098. this.params.minPxPerSec = pxPerSec;
  4099. this.params.scrollParent = true;
  4100. }
  4101. this.drawBuffer();
  4102. this.drawer.progress(this.backend.getPlayedPercents());
  4103. this.drawer.recenter(this.getCurrentTime() / this.getDuration());
  4104. this.fireEvent('zoom', pxPerSec);
  4105. }
  4106. /**
  4107. * Decode buffer and load
  4108. *
  4109. * @private
  4110. * @param {ArrayBuffer} arraybuffer Buffer to process
  4111. */
  4112. }, {
  4113. key: "loadArrayBuffer",
  4114. value: function loadArrayBuffer(arraybuffer) {
  4115. var _this9 = this;
  4116. this.decodeArrayBuffer(arraybuffer, function (data) {
  4117. if (!_this9.isDestroyed) {
  4118. _this9.loadDecodedBuffer(data);
  4119. }
  4120. });
  4121. }
  4122. /**
  4123. * Directly load an externally decoded AudioBuffer
  4124. *
  4125. * @private
  4126. * @param {AudioBuffer} buffer Buffer to process
  4127. * @emits WaveSurfer#ready
  4128. */
  4129. }, {
  4130. key: "loadDecodedBuffer",
  4131. value: function loadDecodedBuffer(buffer) {
  4132. this.backend.load(buffer);
  4133. this.drawBuffer();
  4134. this.isReady = true;
  4135. this.fireEvent('ready');
  4136. }
  4137. /**
  4138. * Loads audio data from a Blob or File object
  4139. *
  4140. * @param {Blob|File} blob Audio data
  4141. * @example
  4142. */
  4143. }, {
  4144. key: "loadBlob",
  4145. value: function loadBlob(blob) {
  4146. var _this10 = this;
  4147. // Create file reader
  4148. var reader = new FileReader();
  4149. reader.addEventListener('progress', function (e) {
  4150. return _this10.onProgress(e);
  4151. });
  4152. reader.addEventListener('load', function (e) {
  4153. return _this10.loadArrayBuffer(e.target.result);
  4154. });
  4155. reader.addEventListener('error', function () {
  4156. return _this10.fireEvent('error', 'Error reading file');
  4157. });
  4158. reader.readAsArrayBuffer(blob);
  4159. this.empty();
  4160. }
  4161. /**
  4162. * Loads audio and re-renders the waveform.
  4163. *
  4164. * @param {string|HTMLMediaElement} url The url of the audio file or the
  4165. * audio element with the audio
  4166. * @param {number[]|Number.<Array[]>} peaks Wavesurfer does not have to decode
  4167. * the audio to render the waveform if this is specified
  4168. * @param {?string} preload (Use with backend `MediaElement` and `MediaElementWebAudio`)
  4169. * `'none'|'metadata'|'auto'` Preload attribute for the media element
  4170. * @param {?number} duration The duration of the audio. This is used to
  4171. * render the peaks data in the correct size for the audio duration (as
  4172. * befits the current `minPxPerSec` and zoom value) without having to decode
  4173. * the audio.
  4174. * @returns {void}
  4175. * @throws Will throw an error if the `url` argument is empty.
  4176. * @example
  4177. * // uses fetch or media element to load file (depending on backend)
  4178. * wavesurfer.load('http://example.com/demo.wav');
  4179. *
  4180. * // setting preload attribute with media element backend and supplying
  4181. * // peaks
  4182. * wavesurfer.load(
  4183. * 'http://example.com/demo.wav',
  4184. * [0.0218, 0.0183, 0.0165, 0.0198, 0.2137, 0.2888],
  4185. * true
  4186. * );
  4187. */
  4188. }, {
  4189. key: "load",
  4190. value: function load(url, peaks, preload, duration) {
  4191. if (!url) {
  4192. throw new Error('url parameter cannot be empty');
  4193. }
  4194. this.empty();
  4195. if (preload) {
  4196. // check whether the preload attribute will be usable and if not log
  4197. // a warning listing the reasons why not and nullify the variable
  4198. var preloadIgnoreReasons = {
  4199. "Preload is not 'auto', 'none' or 'metadata'": ['auto', 'metadata', 'none'].indexOf(preload) === -1,
  4200. 'Peaks are not provided': !peaks,
  4201. "Backend is not of type 'MediaElement' or 'MediaElementWebAudio'": ['MediaElement', 'MediaElementWebAudio'].indexOf(this.params.backend) === -1,
  4202. 'Url is not of type string': typeof url !== 'string'
  4203. };
  4204. var activeReasons = Object.keys(preloadIgnoreReasons).filter(function (reason) {
  4205. return preloadIgnoreReasons[reason];
  4206. });
  4207. if (activeReasons.length) {
  4208. // eslint-disable-next-line no-console
  4209. console.warn('Preload parameter of wavesurfer.load will be ignored because:\n\t- ' + activeReasons.join('\n\t- ')); // stop invalid values from being used
  4210. preload = null;
  4211. }
  4212. }
  4213. switch (this.params.backend) {
  4214. case 'WebAudio':
  4215. return this.loadBuffer(url, peaks, duration);
  4216. case 'MediaElement':
  4217. case 'MediaElementWebAudio':
  4218. return this.loadMediaElement(url, peaks, preload, duration);
  4219. }
  4220. }
  4221. /**
  4222. * Loads audio using Web Audio buffer backend.
  4223. *
  4224. * @private
  4225. * @param {string} url URL of audio file
  4226. * @param {number[]|Number.<Array[]>} peaks Peaks data
  4227. * @param {?number} duration Optional duration of audio file
  4228. * @returns {void}
  4229. */
  4230. }, {
  4231. key: "loadBuffer",
  4232. value: function loadBuffer(url, peaks, duration) {
  4233. var _this11 = this;
  4234. var load = function load(action) {
  4235. if (action) {
  4236. _this11.tmpEvents.push(_this11.once('ready', action));
  4237. }
  4238. return _this11.getArrayBuffer(url, function (data) {
  4239. return _this11.loadArrayBuffer(data);
  4240. });
  4241. };
  4242. if (peaks) {
  4243. this.backend.setPeaks(peaks, duration);
  4244. this.drawBuffer();
  4245. this.tmpEvents.push(this.once('interaction', load));
  4246. } else {
  4247. return load();
  4248. }
  4249. }
  4250. /**
  4251. * Either create a media element, or load an existing media element.
  4252. *
  4253. * @private
  4254. * @param {string|HTMLMediaElement} urlOrElt Either a path to a media file, or an
  4255. * existing HTML5 Audio/Video Element
  4256. * @param {number[]|Number.<Array[]>} peaks Array of peaks. Required to bypass web audio
  4257. * dependency
  4258. * @param {?boolean} preload Set to true if the preload attribute of the
  4259. * audio element should be enabled
  4260. * @param {?number} duration Optional duration of audio file
  4261. */
  4262. }, {
  4263. key: "loadMediaElement",
  4264. value: function loadMediaElement(urlOrElt, peaks, preload, duration) {
  4265. var _this12 = this;
  4266. var url = urlOrElt;
  4267. if (typeof urlOrElt === 'string') {
  4268. this.backend.load(url, this.mediaContainer, peaks, preload);
  4269. } else {
  4270. var elt = urlOrElt;
  4271. this.backend.loadElt(elt, peaks); // If peaks are not provided,
  4272. // url = element.src so we can get peaks with web audio
  4273. url = elt.src;
  4274. }
  4275. this.tmpEvents.push(this.backend.once('canplay', function () {
  4276. // ignore when backend was already destroyed
  4277. if (!_this12.backend.destroyed) {
  4278. _this12.drawBuffer();
  4279. _this12.isReady = true;
  4280. _this12.fireEvent('ready');
  4281. }
  4282. }), this.backend.once('error', function (err) {
  4283. return _this12.fireEvent('error', err);
  4284. }));
  4285. if (peaks) {
  4286. this.backend.setPeaks(peaks, duration);
  4287. this.drawBuffer();
  4288. } // If no pre-decoded peaks are provided, or are provided with
  4289. // forceDecode flag, attempt to download the audio file and decode it
  4290. // with Web Audio.
  4291. if ((!peaks || this.params.forceDecode) && this.backend.supportsWebAudio()) {
  4292. this.getArrayBuffer(url, function (arraybuffer) {
  4293. _this12.decodeArrayBuffer(arraybuffer, function (buffer) {
  4294. _this12.backend.buffer = buffer;
  4295. _this12.backend.setPeaks(null);
  4296. _this12.drawBuffer();
  4297. _this12.fireEvent('waveform-ready');
  4298. });
  4299. });
  4300. }
  4301. }
  4302. /**
  4303. * Decode an array buffer and pass data to a callback
  4304. *
  4305. * @private
  4306. * @param {Object} arraybuffer The array buffer to decode
  4307. * @param {function} callback The function to call on complete
  4308. */
  4309. }, {
  4310. key: "decodeArrayBuffer",
  4311. value: function decodeArrayBuffer(arraybuffer, callback) {
  4312. var _this13 = this;
  4313. this.arraybuffer = arraybuffer;
  4314. this.backend.decodeArrayBuffer(arraybuffer, function (data) {
  4315. // Only use the decoded data if we haven't been destroyed or
  4316. // another decode started in the meantime
  4317. if (!_this13.isDestroyed && _this13.arraybuffer == arraybuffer) {
  4318. callback(data);
  4319. _this13.arraybuffer = null;
  4320. }
  4321. }, function () {
  4322. return _this13.fireEvent('error', 'Error decoding audiobuffer');
  4323. });
  4324. }
  4325. /**
  4326. * Load an array buffer using fetch and pass the result to a callback
  4327. *
  4328. * @param {string} url The URL of the file object
  4329. * @param {function} callback The function to call on complete
  4330. * @returns {util.fetchFile} fetch call
  4331. * @private
  4332. */
  4333. }, {
  4334. key: "getArrayBuffer",
  4335. value: function getArrayBuffer(url, callback) {
  4336. var _this14 = this;
  4337. var options = Object.assign({
  4338. url: url,
  4339. responseType: 'arraybuffer'
  4340. }, this.params.xhr);
  4341. var request = util.fetchFile(options);
  4342. this.currentRequest = request;
  4343. this.tmpEvents.push(request.on('progress', function (e) {
  4344. _this14.onProgress(e);
  4345. }), request.on('success', function (data) {
  4346. callback(data);
  4347. _this14.currentRequest = null;
  4348. }), request.on('error', function (e) {
  4349. _this14.fireEvent('error', e);
  4350. _this14.currentRequest = null;
  4351. }));
  4352. return request;
  4353. }
  4354. /**
  4355. * Called while the audio file is loading
  4356. *
  4357. * @private
  4358. * @param {Event} e Progress event
  4359. * @emits WaveSurfer#loading
  4360. */
  4361. }, {
  4362. key: "onProgress",
  4363. value: function onProgress(e) {
  4364. var percentComplete;
  4365. if (e.lengthComputable) {
  4366. percentComplete = e.loaded / e.total;
  4367. } else {
  4368. // Approximate progress with an asymptotic
  4369. // function, and assume downloads in the 1-3 MB range.
  4370. percentComplete = e.loaded / (e.loaded + 1000000);
  4371. }
  4372. this.fireEvent('loading', Math.round(percentComplete * 100), e.target);
  4373. }
  4374. /**
  4375. * Exports PCM data into a JSON array and opens in a new window.
  4376. *
  4377. * @param {number} length=1024 The scale in which to export the peaks
  4378. * @param {number} accuracy=10000
  4379. * @param {?boolean} noWindow Set to true to disable opening a new
  4380. * window with the JSON
  4381. * @param {number} start Start index
  4382. * @param {number} end End index
  4383. * @return {Promise} Promise that resolves with array of peaks
  4384. */
  4385. }, {
  4386. key: "exportPCM",
  4387. value: function exportPCM(length, accuracy, noWindow, start, end) {
  4388. length = length || 1024;
  4389. start = start || 0;
  4390. accuracy = accuracy || 10000;
  4391. noWindow = noWindow || false;
  4392. var peaks = this.backend.getPeaks(length, start, end);
  4393. var arr = [].map.call(peaks, function (val) {
  4394. return Math.round(val * accuracy) / accuracy;
  4395. });
  4396. return new Promise(function (resolve, reject) {
  4397. var json = JSON.stringify(arr);
  4398. if (!noWindow) {
  4399. window.open('data:application/json;charset=utf-8,' + encodeURIComponent(json));
  4400. }
  4401. resolve(json);
  4402. });
  4403. }
  4404. /**
  4405. * Save waveform image as data URI.
  4406. *
  4407. * The default format is `'image/png'`. Other supported types are
  4408. * `'image/jpeg'` and `'image/webp'`.
  4409. *
  4410. * @param {string} format='image/png' A string indicating the image format.
  4411. * The default format type is `'image/png'`.
  4412. * @param {number} quality=1 A number between 0 and 1 indicating the image
  4413. * quality to use for image formats that use lossy compression such as
  4414. * `'image/jpeg'`` and `'image/webp'`.
  4415. * @param {string} type Image data type to return. Either 'dataURL' (default)
  4416. * or 'blob'.
  4417. * @return {string|string[]|Promise} When using `'dataURL'` type this returns
  4418. * a single data URL or an array of data URLs, one for each canvas. When using
  4419. * `'blob'` type this returns a `Promise` resolving with an array of `Blob`
  4420. * instances, one for each canvas.
  4421. */
  4422. }, {
  4423. key: "exportImage",
  4424. value: function exportImage(format, quality, type) {
  4425. if (!format) {
  4426. format = 'image/png';
  4427. }
  4428. if (!quality) {
  4429. quality = 1;
  4430. }
  4431. if (!type) {
  4432. type = 'dataURL';
  4433. }
  4434. return this.drawer.getImage(format, quality, type);
  4435. }
  4436. /**
  4437. * Cancel any fetch request currently in progress
  4438. */
  4439. }, {
  4440. key: "cancelAjax",
  4441. value: function cancelAjax() {
  4442. if (this.currentRequest && this.currentRequest.controller) {
  4443. // If the current request has a ProgressHandler, then its ReadableStream might need to be cancelled too
  4444. // See: Wavesurfer issue #2042
  4445. // See Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1583815
  4446. if (this.currentRequest._reader) {
  4447. // Ignoring exceptions thrown by call to cancel()
  4448. this.currentRequest._reader.cancel().catch(function (err) {});
  4449. }
  4450. this.currentRequest.controller.abort();
  4451. this.currentRequest = null;
  4452. }
  4453. }
  4454. /**
  4455. * @private
  4456. */
  4457. }, {
  4458. key: "clearTmpEvents",
  4459. value: function clearTmpEvents() {
  4460. this.tmpEvents.forEach(function (e) {
  4461. return e.un();
  4462. });
  4463. }
  4464. /**
  4465. * Display empty waveform.
  4466. */
  4467. }, {
  4468. key: "empty",
  4469. value: function empty() {
  4470. if (!this.backend.isPaused()) {
  4471. this.stop();
  4472. this.backend.disconnectSource();
  4473. }
  4474. this.isReady = false;
  4475. this.cancelAjax();
  4476. this.clearTmpEvents(); // empty drawer
  4477. this.drawer.progress(0);
  4478. this.drawer.setWidth(0);
  4479. this.drawer.drawPeaks({
  4480. length: this.drawer.getWidth()
  4481. }, 0);
  4482. }
  4483. /**
  4484. * Remove events, elements and disconnect WebAudio nodes.
  4485. *
  4486. * @emits WaveSurfer#destroy
  4487. */
  4488. }, {
  4489. key: "destroy",
  4490. value: function destroy() {
  4491. this.destroyAllPlugins();
  4492. this.fireEvent('destroy');
  4493. this.cancelAjax();
  4494. this.clearTmpEvents();
  4495. this.unAll();
  4496. if (this.params.responsive !== false) {
  4497. window.removeEventListener('resize', this._onResize, true);
  4498. window.removeEventListener('orientationchange', this._onResize, true);
  4499. }
  4500. if (this.backend) {
  4501. this.backend.destroy();
  4502. }
  4503. if (this.drawer) {
  4504. this.drawer.destroy();
  4505. }
  4506. this.isDestroyed = true;
  4507. this.isReady = false;
  4508. this.arraybuffer = null;
  4509. }
  4510. }]);
  4511. return WaveSurfer;
  4512. }(util.Observer);
  4513. exports.default = WaveSurfer;
  4514. WaveSurfer.VERSION = "4.1.1";
  4515. WaveSurfer.util = util;
  4516. module.exports = exports.default;
  4517. /***/ }),
  4518. /***/ "./src/webaudio.js":
  4519. /*!*************************!*\
  4520. !*** ./src/webaudio.js ***!
  4521. \*************************/
  4522. /*! no static exports found */
  4523. /***/ (function(module, exports, __webpack_require__) {
  4524. "use strict";
  4525. Object.defineProperty(exports, "__esModule", {
  4526. value: true
  4527. });
  4528. exports.default = void 0;
  4529. var util = _interopRequireWildcard(__webpack_require__(/*! ./util */ "./src/util/index.js"));
  4530. function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; }
  4531. function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
  4532. function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
  4533. function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
  4534. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  4535. function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
  4536. function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
  4537. function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
  4538. function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
  4539. function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
  4540. function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
  4541. function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
  4542. function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
  4543. function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
  4544. // using constants to prevent someone writing the string wrong
  4545. var PLAYING = 'playing';
  4546. var PAUSED = 'paused';
  4547. var FINISHED = 'finished';
  4548. /**
  4549. * WebAudio backend
  4550. *
  4551. * @extends {Observer}
  4552. */
  4553. var WebAudio = /*#__PURE__*/function (_util$Observer) {
  4554. _inherits(WebAudio, _util$Observer);
  4555. var _super = _createSuper(WebAudio);
  4556. _createClass(WebAudio, [{
  4557. key: "supportsWebAudio",
  4558. /** scriptBufferSize: size of the processing buffer */
  4559. /** audioContext: allows to process audio with WebAudio API */
  4560. /** @private */
  4561. /** @private */
  4562. /**
  4563. * Does the browser support this backend
  4564. *
  4565. * @return {boolean} Whether or not this browser supports this backend
  4566. */
  4567. value: function supportsWebAudio() {
  4568. return !!(window.AudioContext || window.webkitAudioContext);
  4569. }
  4570. /**
  4571. * Get the audio context used by this backend or create one
  4572. *
  4573. * @return {AudioContext} Existing audio context, or creates a new one
  4574. */
  4575. }, {
  4576. key: "getAudioContext",
  4577. value: function getAudioContext() {
  4578. if (!window.WaveSurferAudioContext) {
  4579. window.WaveSurferAudioContext = new (window.AudioContext || window.webkitAudioContext)();
  4580. }
  4581. return window.WaveSurferAudioContext;
  4582. }
  4583. /**
  4584. * Get the offline audio context used by this backend or create one
  4585. *
  4586. * @param {number} sampleRate The sample rate to use
  4587. * @return {OfflineAudioContext} Existing offline audio context, or creates
  4588. * a new one
  4589. */
  4590. }, {
  4591. key: "getOfflineAudioContext",
  4592. value: function getOfflineAudioContext(sampleRate) {
  4593. if (!window.WaveSurferOfflineAudioContext) {
  4594. window.WaveSurferOfflineAudioContext = new (window.OfflineAudioContext || window.webkitOfflineAudioContext)(1, 2, sampleRate);
  4595. }
  4596. return window.WaveSurferOfflineAudioContext;
  4597. }
  4598. /**
  4599. * Construct the backend
  4600. *
  4601. * @param {WavesurferParams} params Wavesurfer parameters
  4602. */
  4603. }]);
  4604. function WebAudio(params) {
  4605. var _this$stateBehaviors, _this$states;
  4606. var _this;
  4607. _classCallCheck(this, WebAudio);
  4608. _this = _super.call(this);
  4609. /** @private */
  4610. _this.audioContext = null;
  4611. _this.offlineAudioContext = null;
  4612. _this.stateBehaviors = (_this$stateBehaviors = {}, _defineProperty(_this$stateBehaviors, PLAYING, {
  4613. init: function init() {
  4614. this.addOnAudioProcess();
  4615. },
  4616. getPlayedPercents: function getPlayedPercents() {
  4617. var duration = this.getDuration();
  4618. return this.getCurrentTime() / duration || 0;
  4619. },
  4620. getCurrentTime: function getCurrentTime() {
  4621. return this.startPosition + this.getPlayedTime();
  4622. }
  4623. }), _defineProperty(_this$stateBehaviors, PAUSED, {
  4624. init: function init() {
  4625. this.removeOnAudioProcess();
  4626. },
  4627. getPlayedPercents: function getPlayedPercents() {
  4628. var duration = this.getDuration();
  4629. return this.getCurrentTime() / duration || 0;
  4630. },
  4631. getCurrentTime: function getCurrentTime() {
  4632. return this.startPosition;
  4633. }
  4634. }), _defineProperty(_this$stateBehaviors, FINISHED, {
  4635. init: function init() {
  4636. this.removeOnAudioProcess();
  4637. this.fireEvent('finish');
  4638. },
  4639. getPlayedPercents: function getPlayedPercents() {
  4640. return 1;
  4641. },
  4642. getCurrentTime: function getCurrentTime() {
  4643. return this.getDuration();
  4644. }
  4645. }), _this$stateBehaviors);
  4646. _this.params = params;
  4647. /** ac: Audio Context instance */
  4648. _this.ac = params.audioContext || (_this.supportsWebAudio() ? _this.getAudioContext() : {});
  4649. /**@private */
  4650. _this.lastPlay = _this.ac.currentTime;
  4651. /** @private */
  4652. _this.startPosition = 0;
  4653. /** @private */
  4654. _this.scheduledPause = null;
  4655. /** @private */
  4656. _this.states = (_this$states = {}, _defineProperty(_this$states, PLAYING, Object.create(_this.stateBehaviors[PLAYING])), _defineProperty(_this$states, PAUSED, Object.create(_this.stateBehaviors[PAUSED])), _defineProperty(_this$states, FINISHED, Object.create(_this.stateBehaviors[FINISHED])), _this$states);
  4657. /** @private */
  4658. _this.buffer = null;
  4659. /** @private */
  4660. _this.filters = [];
  4661. /** gainNode: allows to control audio volume */
  4662. _this.gainNode = null;
  4663. /** @private */
  4664. _this.mergedPeaks = null;
  4665. /** @private */
  4666. _this.offlineAc = null;
  4667. /** @private */
  4668. _this.peaks = null;
  4669. /** @private */
  4670. _this.playbackRate = 1;
  4671. /** analyser: provides audio analysis information */
  4672. _this.analyser = null;
  4673. /** scriptNode: allows processing audio */
  4674. _this.scriptNode = null;
  4675. /** @private */
  4676. _this.source = null;
  4677. /** @private */
  4678. _this.splitPeaks = [];
  4679. /** @private */
  4680. _this.state = null;
  4681. /** @private */
  4682. _this.explicitDuration = params.duration;
  4683. /**
  4684. * Boolean indicating if the backend was destroyed.
  4685. */
  4686. _this.destroyed = false;
  4687. return _this;
  4688. }
  4689. /**
  4690. * Initialise the backend, called in `wavesurfer.createBackend()`
  4691. */
  4692. _createClass(WebAudio, [{
  4693. key: "init",
  4694. value: function init() {
  4695. this.createVolumeNode();
  4696. this.createScriptNode();
  4697. this.createAnalyserNode();
  4698. this.setState(PAUSED);
  4699. this.setPlaybackRate(this.params.audioRate);
  4700. this.setLength(0);
  4701. }
  4702. /** @private */
  4703. }, {
  4704. key: "disconnectFilters",
  4705. value: function disconnectFilters() {
  4706. if (this.filters) {
  4707. this.filters.forEach(function (filter) {
  4708. filter && filter.disconnect();
  4709. });
  4710. this.filters = null; // Reconnect direct path
  4711. this.analyser.connect(this.gainNode);
  4712. }
  4713. }
  4714. /**
  4715. * @private
  4716. *
  4717. * @param {string} state The new state
  4718. */
  4719. }, {
  4720. key: "setState",
  4721. value: function setState(state) {
  4722. if (this.state !== this.states[state]) {
  4723. this.state = this.states[state];
  4724. this.state.init.call(this);
  4725. }
  4726. }
  4727. /**
  4728. * Unpacked `setFilters()`
  4729. *
  4730. * @param {...AudioNode} filters One or more filters to set
  4731. */
  4732. }, {
  4733. key: "setFilter",
  4734. value: function setFilter() {
  4735. for (var _len = arguments.length, filters = new Array(_len), _key = 0; _key < _len; _key++) {
  4736. filters[_key] = arguments[_key];
  4737. }
  4738. this.setFilters(filters);
  4739. }
  4740. /**
  4741. * Insert custom Web Audio nodes into the graph
  4742. *
  4743. * @param {AudioNode[]} filters Packed filters array
  4744. * @example
  4745. * const lowpass = wavesurfer.backend.ac.createBiquadFilter();
  4746. * wavesurfer.backend.setFilter(lowpass);
  4747. */
  4748. }, {
  4749. key: "setFilters",
  4750. value: function setFilters(filters) {
  4751. // Remove existing filters
  4752. this.disconnectFilters(); // Insert filters if filter array not empty
  4753. if (filters && filters.length) {
  4754. this.filters = filters; // Disconnect direct path before inserting filters
  4755. this.analyser.disconnect(); // Connect each filter in turn
  4756. filters.reduce(function (prev, curr) {
  4757. prev.connect(curr);
  4758. return curr;
  4759. }, this.analyser).connect(this.gainNode);
  4760. }
  4761. }
  4762. /** Create ScriptProcessorNode to process audio */
  4763. }, {
  4764. key: "createScriptNode",
  4765. value: function createScriptNode() {
  4766. if (this.params.audioScriptProcessor) {
  4767. this.scriptNode = this.params.audioScriptProcessor;
  4768. } else {
  4769. if (this.ac.createScriptProcessor) {
  4770. this.scriptNode = this.ac.createScriptProcessor(WebAudio.scriptBufferSize);
  4771. } else {
  4772. this.scriptNode = this.ac.createJavaScriptNode(WebAudio.scriptBufferSize);
  4773. }
  4774. }
  4775. this.scriptNode.connect(this.ac.destination);
  4776. }
  4777. /** @private */
  4778. }, {
  4779. key: "addOnAudioProcess",
  4780. value: function addOnAudioProcess() {
  4781. var _this2 = this;
  4782. this.scriptNode.onaudioprocess = function () {
  4783. var time = _this2.getCurrentTime();
  4784. if (time >= _this2.getDuration()) {
  4785. _this2.setState(FINISHED);
  4786. _this2.fireEvent('pause');
  4787. } else if (time >= _this2.scheduledPause) {
  4788. _this2.pause();
  4789. } else if (_this2.state === _this2.states[PLAYING]) {
  4790. _this2.fireEvent('audioprocess', time);
  4791. }
  4792. };
  4793. }
  4794. /** @private */
  4795. }, {
  4796. key: "removeOnAudioProcess",
  4797. value: function removeOnAudioProcess() {
  4798. this.scriptNode.onaudioprocess = function () {};
  4799. }
  4800. /** Create analyser node to perform audio analysis */
  4801. }, {
  4802. key: "createAnalyserNode",
  4803. value: function createAnalyserNode() {
  4804. this.analyser = this.ac.createAnalyser();
  4805. this.analyser.connect(this.gainNode);
  4806. }
  4807. /**
  4808. * Create the gain node needed to control the playback volume.
  4809. *
  4810. */
  4811. }, {
  4812. key: "createVolumeNode",
  4813. value: function createVolumeNode() {
  4814. // Create gain node using the AudioContext
  4815. if (this.ac.createGain) {
  4816. this.gainNode = this.ac.createGain();
  4817. } else {
  4818. this.gainNode = this.ac.createGainNode();
  4819. } // Add the gain node to the graph
  4820. this.gainNode.connect(this.ac.destination);
  4821. }
  4822. /**
  4823. * Set the sink id for the media player
  4824. *
  4825. * @param {string} deviceId String value representing audio device id.
  4826. * @returns {Promise} A Promise that resolves to `undefined` when there
  4827. * are no errors.
  4828. */
  4829. }, {
  4830. key: "setSinkId",
  4831. value: function setSinkId(deviceId) {
  4832. if (deviceId) {
  4833. /**
  4834. * The webaudio API doesn't currently support setting the device
  4835. * output. Here we create an HTMLAudioElement, connect the
  4836. * webaudio stream to that element and setSinkId there.
  4837. */
  4838. var audio = new window.Audio();
  4839. if (!audio.setSinkId) {
  4840. return Promise.reject(new Error('setSinkId is not supported in your browser'));
  4841. }
  4842. audio.autoplay = true;
  4843. var dest = this.ac.createMediaStreamDestination();
  4844. this.gainNode.disconnect();
  4845. this.gainNode.connect(dest);
  4846. audio.srcObject = dest.stream;
  4847. return audio.setSinkId(deviceId);
  4848. } else {
  4849. return Promise.reject(new Error('Invalid deviceId: ' + deviceId));
  4850. }
  4851. }
  4852. /**
  4853. * Set the audio volume
  4854. *
  4855. * @param {number} value A floating point value between 0 and 1.
  4856. */
  4857. }, {
  4858. key: "setVolume",
  4859. value: function setVolume(value) {
  4860. this.gainNode.gain.setValueAtTime(value, this.ac.currentTime);
  4861. }
  4862. /**
  4863. * Get the current volume
  4864. *
  4865. * @return {number} value A floating point value between 0 and 1.
  4866. */
  4867. }, {
  4868. key: "getVolume",
  4869. value: function getVolume() {
  4870. return this.gainNode.gain.value;
  4871. }
  4872. /**
  4873. * Decode an array buffer and pass data to a callback
  4874. *
  4875. * @private
  4876. * @param {ArrayBuffer} arraybuffer The array buffer to decode
  4877. * @param {function} callback The function to call on complete.
  4878. * @param {function} errback The function to call on error.
  4879. */
  4880. }, {
  4881. key: "decodeArrayBuffer",
  4882. value: function decodeArrayBuffer(arraybuffer, callback, errback) {
  4883. if (!this.offlineAc) {
  4884. this.offlineAc = this.getOfflineAudioContext(this.ac && this.ac.sampleRate ? this.ac.sampleRate : 44100);
  4885. }
  4886. this.offlineAc.decodeAudioData(arraybuffer, function (data) {
  4887. return callback(data);
  4888. }, errback);
  4889. }
  4890. /**
  4891. * Set pre-decoded peaks
  4892. *
  4893. * @param {number[]|Number.<Array[]>} peaks Peaks data
  4894. * @param {?number} duration Explicit duration
  4895. */
  4896. }, {
  4897. key: "setPeaks",
  4898. value: function setPeaks(peaks, duration) {
  4899. if (duration != null) {
  4900. this.explicitDuration = duration;
  4901. }
  4902. this.peaks = peaks;
  4903. }
  4904. /**
  4905. * Set the rendered length (different from the length of the audio)
  4906. *
  4907. * @param {number} length The rendered length
  4908. */
  4909. }, {
  4910. key: "setLength",
  4911. value: function setLength(length) {
  4912. // No resize, we can preserve the cached peaks.
  4913. if (this.mergedPeaks && length == 2 * this.mergedPeaks.length - 1 + 2) {
  4914. return;
  4915. }
  4916. this.splitPeaks = [];
  4917. this.mergedPeaks = []; // Set the last element of the sparse array so the peak arrays are
  4918. // appropriately sized for other calculations.
  4919. var channels = this.buffer ? this.buffer.numberOfChannels : 1;
  4920. var c;
  4921. for (c = 0; c < channels; c++) {
  4922. this.splitPeaks[c] = [];
  4923. this.splitPeaks[c][2 * (length - 1)] = 0;
  4924. this.splitPeaks[c][2 * (length - 1) + 1] = 0;
  4925. }
  4926. this.mergedPeaks[2 * (length - 1)] = 0;
  4927. this.mergedPeaks[2 * (length - 1) + 1] = 0;
  4928. }
  4929. /**
  4930. * Compute the max and min value of the waveform when broken into <length> subranges.
  4931. *
  4932. * @param {number} length How many subranges to break the waveform into.
  4933. * @param {number} first First sample in the required range.
  4934. * @param {number} last Last sample in the required range.
  4935. * @return {number[]|Number.<Array[]>} Array of 2*<length> peaks or array of arrays of
  4936. * peaks consisting of (max, min) values for each subrange.
  4937. */
  4938. }, {
  4939. key: "getPeaks",
  4940. value: function getPeaks(length, first, last) {
  4941. if (this.peaks) {
  4942. return this.peaks;
  4943. }
  4944. if (!this.buffer) {
  4945. return [];
  4946. }
  4947. first = first || 0;
  4948. last = last || length - 1;
  4949. this.setLength(length);
  4950. if (!this.buffer) {
  4951. return this.params.splitChannels ? this.splitPeaks : this.mergedPeaks;
  4952. }
  4953. /**
  4954. * The following snippet fixes a buffering data issue on the Safari
  4955. * browser which returned undefined It creates the missing buffer based
  4956. * on 1 channel, 4096 samples and the sampleRate from the current
  4957. * webaudio context 4096 samples seemed to be the best fit for rendering
  4958. * will review this code once a stable version of Safari TP is out
  4959. */
  4960. if (!this.buffer.length) {
  4961. var newBuffer = this.createBuffer(1, 4096, this.sampleRate);
  4962. this.buffer = newBuffer.buffer;
  4963. }
  4964. var sampleSize = this.buffer.length / length;
  4965. var sampleStep = ~~(sampleSize / 10) || 1;
  4966. var channels = this.buffer.numberOfChannels;
  4967. var c;
  4968. for (c = 0; c < channels; c++) {
  4969. var peaks = this.splitPeaks[c];
  4970. var chan = this.buffer.getChannelData(c);
  4971. var i = void 0;
  4972. for (i = first; i <= last; i++) {
  4973. var start = ~~(i * sampleSize);
  4974. var end = ~~(start + sampleSize);
  4975. /**
  4976. * Initialize the max and min to the first sample of this
  4977. * subrange, so that even if the samples are entirely
  4978. * on one side of zero, we still return the true max and
  4979. * min values in the subrange.
  4980. */
  4981. var min = chan[start];
  4982. var max = min;
  4983. var j = void 0;
  4984. for (j = start; j < end; j += sampleStep) {
  4985. var value = chan[j];
  4986. if (value > max) {
  4987. max = value;
  4988. }
  4989. if (value < min) {
  4990. min = value;
  4991. }
  4992. }
  4993. peaks[2 * i] = max;
  4994. peaks[2 * i + 1] = min;
  4995. if (c == 0 || max > this.mergedPeaks[2 * i]) {
  4996. this.mergedPeaks[2 * i] = max;
  4997. }
  4998. if (c == 0 || min < this.mergedPeaks[2 * i + 1]) {
  4999. this.mergedPeaks[2 * i + 1] = min;
  5000. }
  5001. }
  5002. }
  5003. return this.params.splitChannels ? this.splitPeaks : this.mergedPeaks;
  5004. }
  5005. /**
  5006. * Get the position from 0 to 1
  5007. *
  5008. * @return {number} Position
  5009. */
  5010. }, {
  5011. key: "getPlayedPercents",
  5012. value: function getPlayedPercents() {
  5013. return this.state.getPlayedPercents.call(this);
  5014. }
  5015. /** @private */
  5016. }, {
  5017. key: "disconnectSource",
  5018. value: function disconnectSource() {
  5019. if (this.source) {
  5020. this.source.disconnect();
  5021. }
  5022. }
  5023. /**
  5024. * Destroy all references with WebAudio, disconnecting audio nodes and closing Audio Context
  5025. */
  5026. }, {
  5027. key: "destroyWebAudio",
  5028. value: function destroyWebAudio() {
  5029. this.disconnectFilters();
  5030. this.disconnectSource();
  5031. this.gainNode.disconnect();
  5032. this.scriptNode.disconnect();
  5033. this.analyser.disconnect(); // close the audioContext if closeAudioContext option is set to true
  5034. if (this.params.closeAudioContext) {
  5035. // check if browser supports AudioContext.close()
  5036. if (typeof this.ac.close === 'function' && this.ac.state != 'closed') {
  5037. this.ac.close();
  5038. } // clear the reference to the audiocontext
  5039. this.ac = null; // clear the actual audiocontext, either passed as param or the
  5040. // global singleton
  5041. if (!this.params.audioContext) {
  5042. window.WaveSurferAudioContext = null;
  5043. } else {
  5044. this.params.audioContext = null;
  5045. } // clear the offlineAudioContext
  5046. window.WaveSurferOfflineAudioContext = null;
  5047. }
  5048. }
  5049. /**
  5050. * This is called when wavesurfer is destroyed
  5051. */
  5052. }, {
  5053. key: "destroy",
  5054. value: function destroy() {
  5055. if (!this.isPaused()) {
  5056. this.pause();
  5057. }
  5058. this.unAll();
  5059. this.buffer = null;
  5060. this.destroyed = true;
  5061. this.destroyWebAudio();
  5062. }
  5063. /**
  5064. * Loaded a decoded audio buffer
  5065. *
  5066. * @param {Object} buffer Decoded audio buffer to load
  5067. */
  5068. }, {
  5069. key: "load",
  5070. value: function load(buffer) {
  5071. this.startPosition = 0;
  5072. this.lastPlay = this.ac.currentTime;
  5073. this.buffer = buffer;
  5074. this.createSource();
  5075. }
  5076. /** @private */
  5077. }, {
  5078. key: "createSource",
  5079. value: function createSource() {
  5080. this.disconnectSource();
  5081. this.source = this.ac.createBufferSource(); // adjust for old browsers
  5082. this.source.start = this.source.start || this.source.noteGrainOn;
  5083. this.source.stop = this.source.stop || this.source.noteOff;
  5084. this.source.playbackRate.setValueAtTime(this.playbackRate, this.ac.currentTime);
  5085. this.source.buffer = this.buffer;
  5086. this.source.connect(this.analyser);
  5087. }
  5088. /**
  5089. * @private
  5090. *
  5091. * some browsers require an explicit call to #resume before they will play back audio
  5092. */
  5093. }, {
  5094. key: "resumeAudioContext",
  5095. value: function resumeAudioContext() {
  5096. if (this.ac.state == 'suspended') {
  5097. this.ac.resume && this.ac.resume();
  5098. }
  5099. }
  5100. /**
  5101. * Used by `wavesurfer.isPlaying()` and `wavesurfer.playPause()`
  5102. *
  5103. * @return {boolean} Whether or not this backend is currently paused
  5104. */
  5105. }, {
  5106. key: "isPaused",
  5107. value: function isPaused() {
  5108. return this.state !== this.states[PLAYING];
  5109. }
  5110. /**
  5111. * Used by `wavesurfer.getDuration()`
  5112. *
  5113. * @return {number} Duration of loaded buffer
  5114. */
  5115. }, {
  5116. key: "getDuration",
  5117. value: function getDuration() {
  5118. if (this.explicitDuration) {
  5119. return this.explicitDuration;
  5120. }
  5121. if (!this.buffer) {
  5122. return 0;
  5123. }
  5124. return this.buffer.duration;
  5125. }
  5126. /**
  5127. * Used by `wavesurfer.seekTo()`
  5128. *
  5129. * @param {number} start Position to start at in seconds
  5130. * @param {number} end Position to end at in seconds
  5131. * @return {{start: number, end: number}} Object containing start and end
  5132. * positions
  5133. */
  5134. }, {
  5135. key: "seekTo",
  5136. value: function seekTo(start, end) {
  5137. if (!this.buffer) {
  5138. return;
  5139. }
  5140. this.scheduledPause = null;
  5141. if (start == null) {
  5142. start = this.getCurrentTime();
  5143. if (start >= this.getDuration()) {
  5144. start = 0;
  5145. }
  5146. }
  5147. if (end == null) {
  5148. end = this.getDuration();
  5149. }
  5150. this.startPosition = start;
  5151. this.lastPlay = this.ac.currentTime;
  5152. if (this.state === this.states[FINISHED]) {
  5153. this.setState(PAUSED);
  5154. }
  5155. return {
  5156. start: start,
  5157. end: end
  5158. };
  5159. }
  5160. /**
  5161. * Get the playback position in seconds
  5162. *
  5163. * @return {number} The playback position in seconds
  5164. */
  5165. }, {
  5166. key: "getPlayedTime",
  5167. value: function getPlayedTime() {
  5168. return (this.ac.currentTime - this.lastPlay) * this.playbackRate;
  5169. }
  5170. /**
  5171. * Plays the loaded audio region.
  5172. *
  5173. * @param {number} start Start offset in seconds, relative to the beginning
  5174. * of a clip.
  5175. * @param {number} end When to stop relative to the beginning of a clip.
  5176. */
  5177. }, {
  5178. key: "play",
  5179. value: function play(start, end) {
  5180. if (!this.buffer) {
  5181. return;
  5182. } // need to re-create source on each playback
  5183. this.createSource();
  5184. var adjustedTime = this.seekTo(start, end);
  5185. start = adjustedTime.start;
  5186. end = adjustedTime.end;
  5187. this.scheduledPause = end;
  5188. this.source.start(0, start);
  5189. this.resumeAudioContext();
  5190. this.setState(PLAYING);
  5191. this.fireEvent('play');
  5192. }
  5193. /**
  5194. * Pauses the loaded audio.
  5195. */
  5196. }, {
  5197. key: "pause",
  5198. value: function pause() {
  5199. this.scheduledPause = null;
  5200. this.startPosition += this.getPlayedTime();
  5201. this.source && this.source.stop(0);
  5202. this.setState(PAUSED);
  5203. this.fireEvent('pause');
  5204. }
  5205. /**
  5206. * Returns the current time in seconds relative to the audio-clip's
  5207. * duration.
  5208. *
  5209. * @return {number} The current time in seconds
  5210. */
  5211. }, {
  5212. key: "getCurrentTime",
  5213. value: function getCurrentTime() {
  5214. return this.state.getCurrentTime.call(this);
  5215. }
  5216. /**
  5217. * Returns the current playback rate. (0=no playback, 1=normal playback)
  5218. *
  5219. * @return {number} The current playback rate
  5220. */
  5221. }, {
  5222. key: "getPlaybackRate",
  5223. value: function getPlaybackRate() {
  5224. return this.playbackRate;
  5225. }
  5226. /**
  5227. * Set the audio source playback rate.
  5228. *
  5229. * @param {number} value The playback rate to use
  5230. */
  5231. }, {
  5232. key: "setPlaybackRate",
  5233. value: function setPlaybackRate(value) {
  5234. value = value || 1;
  5235. if (this.isPaused()) {
  5236. this.playbackRate = value;
  5237. } else {
  5238. this.pause();
  5239. this.playbackRate = value;
  5240. this.play();
  5241. }
  5242. }
  5243. /**
  5244. * Set a point in seconds for playback to stop at.
  5245. *
  5246. * @param {number} end Position to end at
  5247. * @version 3.3.0
  5248. */
  5249. }, {
  5250. key: "setPlayEnd",
  5251. value: function setPlayEnd(end) {
  5252. this.scheduledPause = end;
  5253. }
  5254. }]);
  5255. return WebAudio;
  5256. }(util.Observer);
  5257. exports.default = WebAudio;
  5258. WebAudio.scriptBufferSize = 256;
  5259. module.exports = exports.default;
  5260. /***/ })
  5261. /******/ });
  5262. });
  5263. //# sourceMappingURL=wavesurfer.js.map