12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248 |
- /*!
- * wavesurfer.js 4.1.1 (2020-09-25)
- * https://wavesurfer-js.org
- * @license BSD-3-Clause
- */
- (function webpackUniversalModuleDefinition(root, factory) {
- if(typeof exports === 'object' && typeof module === 'object')
- module.exports = factory();
- else if(typeof define === 'function' && define.amd)
- define("WaveSurfer", [], factory);
- else if(typeof exports === 'object')
- exports["WaveSurfer"] = factory();
- else
- root["WaveSurfer"] = factory();
- })(this, function() {
- return /******/ (function(modules) { // webpackBootstrap
- /******/ // The module cache
- /******/ var installedModules = {};
- /******/
- /******/ // The require function
- /******/ function __webpack_require__(moduleId) {
- /******/
- /******/ // Check if module is in cache
- /******/ if(installedModules[moduleId]) {
- /******/ return installedModules[moduleId].exports;
- /******/ }
- /******/ // Create a new module (and put it into the cache)
- /******/ var module = installedModules[moduleId] = {
- /******/ i: moduleId,
- /******/ l: false,
- /******/ exports: {}
- /******/ };
- /******/
- /******/ // Execute the module function
- /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
- /******/
- /******/ // Flag the module as loaded
- /******/ module.l = true;
- /******/
- /******/ // Return the exports of the module
- /******/ return module.exports;
- /******/ }
- /******/
- /******/
- /******/ // expose the modules object (__webpack_modules__)
- /******/ __webpack_require__.m = modules;
- /******/
- /******/ // expose the module cache
- /******/ __webpack_require__.c = installedModules;
- /******/
- /******/ // define getter function for harmony exports
- /******/ __webpack_require__.d = function(exports, name, getter) {
- /******/ if(!__webpack_require__.o(exports, name)) {
- /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
- /******/ }
- /******/ };
- /******/
- /******/ // define __esModule on exports
- /******/ __webpack_require__.r = function(exports) {
- /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
- /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
- /******/ }
- /******/ Object.defineProperty(exports, '__esModule', { value: true });
- /******/ };
- /******/
- /******/ // create a fake namespace object
- /******/ // mode & 1: value is a module id, require it
- /******/ // mode & 2: merge all properties of value into the ns
- /******/ // mode & 4: return value when already ns object
- /******/ // mode & 8|1: behave like require
- /******/ __webpack_require__.t = function(value, mode) {
- /******/ if(mode & 1) value = __webpack_require__(value);
- /******/ if(mode & 8) return value;
- /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
- /******/ var ns = Object.create(null);
- /******/ __webpack_require__.r(ns);
- /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
- /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
- /******/ return ns;
- /******/ };
- /******/
- /******/ // getDefaultExport function for compatibility with non-harmony modules
- /******/ __webpack_require__.n = function(module) {
- /******/ var getter = module && module.__esModule ?
- /******/ function getDefault() { return module['default']; } :
- /******/ function getModuleExports() { return module; };
- /******/ __webpack_require__.d(getter, 'a', getter);
- /******/ return getter;
- /******/ };
- /******/
- /******/ // Object.prototype.hasOwnProperty.call
- /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
- /******/
- /******/ // __webpack_public_path__
- /******/ __webpack_require__.p = "";
- /******/
- /******/
- /******/ // Load entry module and return exports
- /******/ return __webpack_require__(__webpack_require__.s = "./src/wavesurfer.js");
- /******/ })
- /************************************************************************/
- /******/ ({
- /***/ "./node_modules/debounce/index.js":
- /*!****************************************!*\
- !*** ./node_modules/debounce/index.js ***!
- \****************************************/
- /*! no static exports found */
- /***/ (function(module, exports) {
- /**
- * Returns a function, that, as long as it continues to be invoked, will not
- * be triggered. The function will be called after it stops being called for
- * N milliseconds. If `immediate` is passed, trigger the function on the
- * leading edge, instead of the trailing. The function also has a property 'clear'
- * that is a function which will clear the timer to prevent previously scheduled executions.
- *
- * @source underscore.js
- * @see http://unscriptable.com/2009/03/20/debouncing-javascript-methods/
- * @param {Function} function to wrap
- * @param {Number} timeout in ms (`100`)
- * @param {Boolean} whether to execute at the beginning (`false`)
- * @api public
- */
- function debounce(func, wait, immediate){
- var timeout, args, context, timestamp, result;
- if (null == wait) wait = 100;
- function later() {
- var last = Date.now() - timestamp;
- if (last < wait && last >= 0) {
- timeout = setTimeout(later, wait - last);
- } else {
- timeout = null;
- if (!immediate) {
- result = func.apply(context, args);
- context = args = null;
- }
- }
- };
- var debounced = function(){
- context = this;
- args = arguments;
- timestamp = Date.now();
- var callNow = immediate && !timeout;
- if (!timeout) timeout = setTimeout(later, wait);
- if (callNow) {
- result = func.apply(context, args);
- context = args = null;
- }
- return result;
- };
- debounced.clear = function() {
- if (timeout) {
- clearTimeout(timeout);
- timeout = null;
- }
- };
-
- debounced.flush = function() {
- if (timeout) {
- result = func.apply(context, args);
- context = args = null;
-
- clearTimeout(timeout);
- timeout = null;
- }
- };
- return debounced;
- };
- // Adds compatibility for ES modules
- debounce.debounce = debounce;
- module.exports = debounce;
- /***/ }),
- /***/ "./src/drawer.canvasentry.js":
- /*!***********************************!*\
- !*** ./src/drawer.canvasentry.js ***!
- \***********************************/
- /*! no static exports found */
- /***/ (function(module, exports, __webpack_require__) {
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
- var _style = _interopRequireDefault(__webpack_require__(/*! ./util/style */ "./src/util/style.js"));
- var _getId = _interopRequireDefault(__webpack_require__(/*! ./util/get-id */ "./src/util/get-id.js"));
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
- 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); } }
- function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
- /**
- * The `CanvasEntry` class represents an element consisting of a wave `canvas`
- * and an (optional) progress wave `canvas`.
- *
- * The `MultiCanvas` renderer uses one or more `CanvasEntry` instances to
- * render a waveform, depending on the zoom level.
- */
- var CanvasEntry = /*#__PURE__*/function () {
- function CanvasEntry() {
- _classCallCheck(this, CanvasEntry);
- /**
- * The wave node
- *
- * @type {HTMLCanvasElement}
- */
- this.wave = null;
- /**
- * The wave canvas rendering context
- *
- * @type {CanvasRenderingContext2D}
- */
- this.waveCtx = null;
- /**
- * The (optional) progress wave node
- *
- * @type {HTMLCanvasElement}
- */
- this.progress = null;
- /**
- * The (optional) progress wave canvas rendering context
- *
- * @type {CanvasRenderingContext2D}
- */
- this.progressCtx = null;
- /**
- * Start of the area the canvas should render, between 0 and 1
- *
- * @type {number}
- */
- this.start = 0;
- /**
- * End of the area the canvas should render, between 0 and 1
- *
- * @type {number}
- */
- this.end = 1;
- /**
- * Unique identifier for this entry
- *
- * @type {string}
- */
- this.id = (0, _getId.default)(typeof this.constructor.name !== 'undefined' ? this.constructor.name.toLowerCase() + '_' : 'canvasentry_');
- /**
- * Canvas 2d context attributes
- *
- * @type {object}
- */
- this.canvasContextAttributes = {};
- }
- /**
- * Store the wave canvas element and create the 2D rendering context
- *
- * @param {HTMLCanvasElement} element The wave `canvas` element.
- */
- _createClass(CanvasEntry, [{
- key: "initWave",
- value: function initWave(element) {
- this.wave = element;
- this.waveCtx = this.wave.getContext('2d', this.canvasContextAttributes);
- }
- /**
- * Store the progress wave canvas element and create the 2D rendering
- * context
- *
- * @param {HTMLCanvasElement} element The progress wave `canvas` element.
- */
- }, {
- key: "initProgress",
- value: function initProgress(element) {
- this.progress = element;
- this.progressCtx = this.progress.getContext('2d', this.canvasContextAttributes);
- }
- /**
- * Update the dimensions
- *
- * @param {number} elementWidth Width of the entry
- * @param {number} totalWidth Total width of the multi canvas renderer
- * @param {number} width The new width of the element
- * @param {number} height The new height of the element
- */
- }, {
- key: "updateDimensions",
- value: function updateDimensions(elementWidth, totalWidth, width, height) {
- // where the canvas starts and ends in the waveform, represented as a
- // decimal between 0 and 1
- this.start = this.wave.offsetLeft / totalWidth || 0;
- this.end = this.start + elementWidth / totalWidth; // set wave canvas dimensions
- this.wave.width = width;
- this.wave.height = height;
- var elementSize = {
- width: elementWidth + 'px'
- };
- (0, _style.default)(this.wave, elementSize);
- if (this.hasProgressCanvas) {
- // set progress canvas dimensions
- this.progress.width = width;
- this.progress.height = height;
- (0, _style.default)(this.progress, elementSize);
- }
- }
- /**
- * Clear the wave and progress rendering contexts
- */
- }, {
- key: "clearWave",
- value: function clearWave() {
- // wave
- this.waveCtx.clearRect(0, 0, this.waveCtx.canvas.width, this.waveCtx.canvas.height); // progress
- if (this.hasProgressCanvas) {
- this.progressCtx.clearRect(0, 0, this.progressCtx.canvas.width, this.progressCtx.canvas.height);
- }
- }
- /**
- * Set the fill styles for wave and progress
- *
- * @param {string} waveColor Fill color for the wave canvas
- * @param {?string} progressColor Fill color for the progress canvas
- */
- }, {
- key: "setFillStyles",
- value: function setFillStyles(waveColor, progressColor) {
- this.waveCtx.fillStyle = waveColor;
- if (this.hasProgressCanvas) {
- this.progressCtx.fillStyle = progressColor;
- }
- }
- /**
- * Draw a rectangle for wave and progress
- *
- * @param {number} x X start position
- * @param {number} y Y start position
- * @param {number} width Width of the rectangle
- * @param {number} height Height of the rectangle
- * @param {number} radius Radius of the rectangle
- */
- }, {
- key: "fillRects",
- value: function fillRects(x, y, width, height, radius) {
- this.fillRectToContext(this.waveCtx, x, y, width, height, radius);
- if (this.hasProgressCanvas) {
- this.fillRectToContext(this.progressCtx, x, y, width, height, radius);
- }
- }
- /**
- * Draw the actual rectangle on a `canvas` element
- *
- * @param {CanvasRenderingContext2D} ctx Rendering context of target canvas
- * @param {number} x X start position
- * @param {number} y Y start position
- * @param {number} width Width of the rectangle
- * @param {number} height Height of the rectangle
- * @param {number} radius Radius of the rectangle
- */
- }, {
- key: "fillRectToContext",
- value: function fillRectToContext(ctx, x, y, width, height, radius) {
- if (!ctx) {
- return;
- }
- if (radius) {
- this.drawRoundedRect(ctx, x, y, width, height, radius);
- } else {
- ctx.fillRect(x, y, width, height);
- }
- }
- /**
- * Draw a rounded rectangle on Canvas
- *
- * @param {CanvasRenderingContext2D} ctx Canvas context
- * @param {number} x X-position of the rectangle
- * @param {number} y Y-position of the rectangle
- * @param {number} width Width of the rectangle
- * @param {number} height Height of the rectangle
- * @param {number} radius Radius of the rectangle
- *
- * @return {void}
- * @example drawRoundedRect(ctx, 50, 50, 5, 10, 3)
- */
- }, {
- key: "drawRoundedRect",
- value: function drawRoundedRect(ctx, x, y, width, height, radius) {
- if (height === 0) {
- return;
- } // peaks are float values from -1 to 1. Use absolute height values in
- // order to correctly calculate rounded rectangle coordinates
- if (height < 0) {
- height *= -1;
- y -= height;
- }
- ctx.beginPath();
- ctx.moveTo(x + radius, y);
- ctx.lineTo(x + width - radius, y);
- ctx.quadraticCurveTo(x + width, y, x + width, y + radius);
- ctx.lineTo(x + width, y + height - radius);
- ctx.quadraticCurveTo(x + width, y + height, x + width - radius, y + height);
- ctx.lineTo(x + radius, y + height);
- ctx.quadraticCurveTo(x, y + height, x, y + height - radius);
- ctx.lineTo(x, y + radius);
- ctx.quadraticCurveTo(x, y, x + radius, y);
- ctx.closePath();
- ctx.fill();
- }
- /**
- * Render the actual wave and progress lines
- *
- * @param {number[]} peaks Array with peaks data
- * @param {number} absmax Maximum peak value (absolute)
- * @param {number} halfH Half the height of the waveform
- * @param {number} offsetY Offset to the top
- * @param {number} start The x-offset of the beginning of the area that
- * should be rendered
- * @param {number} end The x-offset of the end of the area that
- * should be rendered
- */
- }, {
- key: "drawLines",
- value: function drawLines(peaks, absmax, halfH, offsetY, start, end) {
- this.drawLineToContext(this.waveCtx, peaks, absmax, halfH, offsetY, start, end);
- if (this.hasProgressCanvas) {
- this.drawLineToContext(this.progressCtx, peaks, absmax, halfH, offsetY, start, end);
- }
- }
- /**
- * Render the actual waveform line on a `canvas` element
- *
- * @param {CanvasRenderingContext2D} ctx Rendering context of target canvas
- * @param {number[]} peaks Array with peaks data
- * @param {number} absmax Maximum peak value (absolute)
- * @param {number} halfH Half the height of the waveform
- * @param {number} offsetY Offset to the top
- * @param {number} start The x-offset of the beginning of the area that
- * should be rendered
- * @param {number} end The x-offset of the end of the area that
- * should be rendered
- */
- }, {
- key: "drawLineToContext",
- value: function drawLineToContext(ctx, peaks, absmax, halfH, offsetY, start, end) {
- if (!ctx) {
- return;
- }
- var length = peaks.length / 2;
- var first = Math.round(length * this.start); // use one more peak value to make sure we join peaks at ends -- unless,
- // of course, this is the last canvas
- var last = Math.round(length * this.end) + 1;
- var canvasStart = first;
- var canvasEnd = last;
- var scale = this.wave.width / (canvasEnd - canvasStart - 1); // optimization
- var halfOffset = halfH + offsetY;
- var absmaxHalf = absmax / halfH;
- ctx.beginPath();
- ctx.moveTo((canvasStart - first) * scale, halfOffset);
- ctx.lineTo((canvasStart - first) * scale, halfOffset - Math.round((peaks[2 * canvasStart] || 0) / absmaxHalf));
- var i, peak, h;
- for (i = canvasStart; i < canvasEnd; i++) {
- peak = peaks[2 * i] || 0;
- h = Math.round(peak / absmaxHalf);
- ctx.lineTo((i - first) * scale + this.halfPixel, halfOffset - h);
- } // draw the bottom edge going backwards, to make a single
- // closed hull to fill
- var j = canvasEnd - 1;
- for (j; j >= canvasStart; j--) {
- peak = peaks[2 * j + 1] || 0;
- h = Math.round(peak / absmaxHalf);
- ctx.lineTo((j - first) * scale + this.halfPixel, halfOffset - h);
- }
- ctx.lineTo((canvasStart - first) * scale, halfOffset - Math.round((peaks[2 * canvasStart + 1] || 0) / absmaxHalf));
- ctx.closePath();
- ctx.fill();
- }
- /**
- * Destroys this entry
- */
- }, {
- key: "destroy",
- value: function destroy() {
- this.waveCtx = null;
- this.wave = null;
- this.progressCtx = null;
- this.progress = null;
- }
- /**
- * Return image data of the wave `canvas` element
- *
- * When using a `type` of `'blob'`, this will return a `Promise` that
- * resolves with a `Blob` instance.
- *
- * @param {string} format='image/png' An optional value of a format type.
- * @param {number} quality=0.92 An optional value between 0 and 1.
- * @param {string} type='dataURL' Either 'dataURL' or 'blob'.
- * @return {string|Promise} When using the default `'dataURL'` `type` this
- * returns a data URL. When using the `'blob'` `type` this returns a
- * `Promise` that resolves with a `Blob` instance.
- */
- }, {
- key: "getImage",
- value: function getImage(format, quality, type) {
- var _this = this;
- if (type === 'blob') {
- return new Promise(function (resolve) {
- _this.wave.toBlob(resolve, format, quality);
- });
- } else if (type === 'dataURL') {
- return this.wave.toDataURL(format, quality);
- }
- }
- }]);
- return CanvasEntry;
- }();
- exports.default = CanvasEntry;
- module.exports = exports.default;
- /***/ }),
- /***/ "./src/drawer.js":
- /*!***********************!*\
- !*** ./src/drawer.js ***!
- \***********************/
- /*! no static exports found */
- /***/ (function(module, exports, __webpack_require__) {
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
- var util = _interopRequireWildcard(__webpack_require__(/*! ./util */ "./src/util/index.js"));
- function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; }
- 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; }
- 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); }
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
- 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); } }
- function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
- 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); }
- function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
- 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); }; }
- function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
- function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
- 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; } }
- function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
- /**
- * Parent class for renderers
- *
- * @extends {Observer}
- */
- var Drawer = /*#__PURE__*/function (_util$Observer) {
- _inherits(Drawer, _util$Observer);
- var _super = _createSuper(Drawer);
- /**
- * @param {HTMLElement} container The container node of the wavesurfer instance
- * @param {WavesurferParams} params The wavesurfer initialisation options
- */
- function Drawer(container, params) {
- var _this;
- _classCallCheck(this, Drawer);
- _this = _super.call(this);
- _this.container = container;
- /**
- * @type {WavesurferParams}
- */
- _this.params = params;
- /**
- * The width of the renderer
- * @type {number}
- */
- _this.width = 0;
- /**
- * The height of the renderer
- * @type {number}
- */
- _this.height = params.height * _this.params.pixelRatio;
- _this.lastPos = 0;
- /**
- * The `<wave>` element which is added to the container
- * @type {HTMLElement}
- */
- _this.wrapper = null;
- return _this;
- }
- /**
- * Alias of `util.style`
- *
- * @param {HTMLElement} el The element that the styles will be applied to
- * @param {Object} styles The map of propName: attribute, both are used as-is
- * @return {HTMLElement} el
- */
- _createClass(Drawer, [{
- key: "style",
- value: function style(el, styles) {
- return util.style(el, styles);
- }
- /**
- * Create the wrapper `<wave>` element, style it and set up the events for
- * interaction
- */
- }, {
- key: "createWrapper",
- value: function createWrapper() {
- this.wrapper = this.container.appendChild(document.createElement('wave'));
- this.style(this.wrapper, {
- display: 'block',
- position: 'relative',
- userSelect: 'none',
- webkitUserSelect: 'none',
- height: this.params.height + 'px'
- });
- if (this.params.fillParent || this.params.scrollParent) {
- this.style(this.wrapper, {
- width: '100%',
- overflowX: this.params.hideScrollbar ? 'hidden' : 'auto',
- overflowY: 'hidden'
- });
- }
- this.setupWrapperEvents();
- }
- /**
- * Handle click event
- *
- * @param {Event} e Click event
- * @param {?boolean} noPrevent Set to true to not call `e.preventDefault()`
- * @return {number} Playback position from 0 to 1
- */
- }, {
- key: "handleEvent",
- value: function handleEvent(e, noPrevent) {
- !noPrevent && e.preventDefault();
- var clientX = e.targetTouches ? e.targetTouches[0].clientX : e.clientX;
- var bbox = this.wrapper.getBoundingClientRect();
- var nominalWidth = this.width;
- var parentWidth = this.getWidth();
- var progress;
- if (!this.params.fillParent && nominalWidth < parentWidth) {
- progress = (this.params.rtl ? bbox.right - clientX : clientX - bbox.left) * (this.params.pixelRatio / nominalWidth) || 0;
- } else {
- progress = ((this.params.rtl ? bbox.right - clientX : clientX - bbox.left) + this.wrapper.scrollLeft) / this.wrapper.scrollWidth || 0;
- }
- return util.clamp(progress, 0, 1);
- }
- }, {
- key: "setupWrapperEvents",
- value: function setupWrapperEvents() {
- var _this2 = this;
- this.wrapper.addEventListener('click', function (e) {
- var scrollbarHeight = _this2.wrapper.offsetHeight - _this2.wrapper.clientHeight;
- if (scrollbarHeight !== 0) {
- // scrollbar is visible. Check if click was on it
- var bbox = _this2.wrapper.getBoundingClientRect();
- if (e.clientY >= bbox.bottom - scrollbarHeight) {
- // ignore mousedown as it was on the scrollbar
- return;
- }
- }
- if (_this2.params.interact) {
- _this2.fireEvent('click', e, _this2.handleEvent(e));
- }
- });
- this.wrapper.addEventListener('dblclick', function (e) {
- if (_this2.params.interact) {
- _this2.fireEvent('dblclick', e, _this2.handleEvent(e));
- }
- });
- this.wrapper.addEventListener('scroll', function (e) {
- return _this2.fireEvent('scroll', e);
- });
- }
- /**
- * Draw peaks on the canvas
- *
- * @param {number[]|Number.<Array[]>} peaks Can also be an array of arrays
- * for split channel rendering
- * @param {number} length The width of the area that should be drawn
- * @param {number} start The x-offset of the beginning of the area that
- * should be rendered
- * @param {number} end The x-offset of the end of the area that should be
- * rendered
- */
- }, {
- key: "drawPeaks",
- value: function drawPeaks(peaks, length, start, end) {
- if (!this.setWidth(length)) {
- this.clearWave();
- }
- this.params.barWidth ? this.drawBars(peaks, 0, start, end) : this.drawWave(peaks, 0, start, end);
- }
- /**
- * Scroll to the beginning
- */
- }, {
- key: "resetScroll",
- value: function resetScroll() {
- if (this.wrapper !== null) {
- this.wrapper.scrollLeft = 0;
- }
- }
- /**
- * Recenter the view-port at a certain percent of the waveform
- *
- * @param {number} percent Value from 0 to 1 on the waveform
- */
- }, {
- key: "recenter",
- value: function recenter(percent) {
- var position = this.wrapper.scrollWidth * percent;
- this.recenterOnPosition(position, true);
- }
- /**
- * Recenter the view-port on a position, either scroll there immediately or
- * in steps of 5 pixels
- *
- * @param {number} position X-offset in pixels
- * @param {boolean} immediate Set to true to immediately scroll somewhere
- */
- }, {
- key: "recenterOnPosition",
- value: function recenterOnPosition(position, immediate) {
- var scrollLeft = this.wrapper.scrollLeft;
- var half = ~~(this.wrapper.clientWidth / 2);
- var maxScroll = this.wrapper.scrollWidth - this.wrapper.clientWidth;
- var target = position - half;
- var offset = target - scrollLeft;
- if (maxScroll == 0) {
- // no need to continue if scrollbar is not there
- return;
- } // if the cursor is currently visible...
- if (!immediate && -half <= offset && offset < half) {
- // set rate at which waveform is centered
- var rate = this.params.autoCenterRate; // make rate depend on width of view and length of waveform
- rate /= half;
- rate *= maxScroll;
- offset = Math.max(-rate, Math.min(rate, offset));
- target = scrollLeft + offset;
- } // limit target to valid range (0 to maxScroll)
- target = Math.max(0, Math.min(maxScroll, target)); // no use attempting to scroll if we're not moving
- if (target != scrollLeft) {
- this.wrapper.scrollLeft = target;
- }
- }
- /**
- * Get the current scroll position in pixels
- *
- * @return {number} Horizontal scroll position in pixels
- */
- }, {
- key: "getScrollX",
- value: function getScrollX() {
- var x = 0;
- if (this.wrapper) {
- var pixelRatio = this.params.pixelRatio;
- x = Math.round(this.wrapper.scrollLeft * pixelRatio); // In cases of elastic scroll (safari with mouse wheel) you can
- // scroll beyond the limits of the container
- // Calculate and floor the scrollable extent to make sure an out
- // of bounds value is not returned
- // Ticket #1312
- if (this.params.scrollParent) {
- var maxScroll = ~~(this.wrapper.scrollWidth * pixelRatio - this.getWidth());
- x = Math.min(maxScroll, Math.max(0, x));
- }
- }
- return x;
- }
- /**
- * Get the width of the container
- *
- * @return {number} The width of the container
- */
- }, {
- key: "getWidth",
- value: function getWidth() {
- return Math.round(this.container.clientWidth * this.params.pixelRatio);
- }
- /**
- * Set the width of the container
- *
- * @param {number} width The new width of the container
- * @return {boolean} Whether the width of the container was updated or not
- */
- }, {
- key: "setWidth",
- value: function setWidth(width) {
- if (this.width == width) {
- return false;
- }
- this.width = width;
- if (this.params.fillParent || this.params.scrollParent) {
- this.style(this.wrapper, {
- width: ''
- });
- } else {
- this.style(this.wrapper, {
- width: ~~(this.width / this.params.pixelRatio) + 'px'
- });
- }
- this.updateSize();
- return true;
- }
- /**
- * Set the height of the container
- *
- * @param {number} height The new height of the container.
- * @return {boolean} Whether the height of the container was updated or not
- */
- }, {
- key: "setHeight",
- value: function setHeight(height) {
- if (height == this.height) {
- return false;
- }
- this.height = height;
- this.style(this.wrapper, {
- height: ~~(this.height / this.params.pixelRatio) + 'px'
- });
- this.updateSize();
- return true;
- }
- /**
- * Called by wavesurfer when progress should be rendered
- *
- * @param {number} progress From 0 to 1
- */
- }, {
- key: "progress",
- value: function progress(_progress) {
- var minPxDelta = 1 / this.params.pixelRatio;
- var pos = Math.round(_progress * this.width) * minPxDelta;
- if (pos < this.lastPos || pos - this.lastPos >= minPxDelta) {
- this.lastPos = pos;
- if (this.params.scrollParent && this.params.autoCenter) {
- var newPos = ~~(this.wrapper.scrollWidth * _progress);
- this.recenterOnPosition(newPos, this.params.autoCenterImmediately);
- }
- this.updateProgress(pos);
- }
- }
- /**
- * This is called when wavesurfer is destroyed
- */
- }, {
- key: "destroy",
- value: function destroy() {
- this.unAll();
- if (this.wrapper) {
- if (this.wrapper.parentNode == this.container) {
- this.container.removeChild(this.wrapper);
- }
- this.wrapper = null;
- }
- }
- /* Renderer-specific methods */
- /**
- * Called after cursor related params have changed.
- *
- * @abstract
- */
- }, {
- key: "updateCursor",
- value: function updateCursor() {}
- /**
- * Called when the size of the container changes so the renderer can adjust
- *
- * @abstract
- */
- }, {
- key: "updateSize",
- value: function updateSize() {}
- /**
- * Draw a waveform with bars
- *
- * @abstract
- * @param {number[]|Number.<Array[]>} peaks Can also be an array of arrays for split channel
- * rendering
- * @param {number} channelIndex The index of the current channel. Normally
- * should be 0
- * @param {number} start The x-offset of the beginning of the area that
- * should be rendered
- * @param {number} end The x-offset of the end of the area that should be
- * rendered
- */
- }, {
- key: "drawBars",
- value: function drawBars(peaks, channelIndex, start, end) {}
- /**
- * Draw a waveform
- *
- * @abstract
- * @param {number[]|Number.<Array[]>} peaks Can also be an array of arrays for split channel
- * rendering
- * @param {number} channelIndex The index of the current channel. Normally
- * should be 0
- * @param {number} start The x-offset of the beginning of the area that
- * should be rendered
- * @param {number} end The x-offset of the end of the area that should be
- * rendered
- */
- }, {
- key: "drawWave",
- value: function drawWave(peaks, channelIndex, start, end) {}
- /**
- * Clear the waveform
- *
- * @abstract
- */
- }, {
- key: "clearWave",
- value: function clearWave() {}
- /**
- * Render the new progress
- *
- * @abstract
- * @param {number} position X-Offset of progress position in pixels
- */
- }, {
- key: "updateProgress",
- value: function updateProgress(position) {}
- }]);
- return Drawer;
- }(util.Observer);
- exports.default = Drawer;
- module.exports = exports.default;
- /***/ }),
- /***/ "./src/drawer.multicanvas.js":
- /*!***********************************!*\
- !*** ./src/drawer.multicanvas.js ***!
- \***********************************/
- /*! no static exports found */
- /***/ (function(module, exports, __webpack_require__) {
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
- var _drawer = _interopRequireDefault(__webpack_require__(/*! ./drawer */ "./src/drawer.js"));
- var util = _interopRequireWildcard(__webpack_require__(/*! ./util */ "./src/util/index.js"));
- var _drawer2 = _interopRequireDefault(__webpack_require__(/*! ./drawer.canvasentry */ "./src/drawer.canvasentry.js"));
- function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; }
- 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; }
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
- 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); }
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
- 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); } }
- function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
- 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); }
- function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
- 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); }; }
- function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
- function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
- 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; } }
- function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
- /**
- * MultiCanvas renderer for wavesurfer. Is currently the default and sole
- * builtin renderer.
- *
- * A `MultiCanvas` consists of one or more `CanvasEntry` instances, depending
- * on the zoom level.
- */
- var MultiCanvas = /*#__PURE__*/function (_Drawer) {
- _inherits(MultiCanvas, _Drawer);
- var _super = _createSuper(MultiCanvas);
- /**
- * @param {HTMLElement} container The container node of the wavesurfer instance
- * @param {WavesurferParams} params The wavesurfer initialisation options
- */
- function MultiCanvas(container, params) {
- var _this;
- _classCallCheck(this, MultiCanvas);
- _this = _super.call(this, container, params);
- /**
- * @type {number}
- */
- _this.maxCanvasWidth = params.maxCanvasWidth;
- /**
- * @type {number}
- */
- _this.maxCanvasElementWidth = Math.round(params.maxCanvasWidth / params.pixelRatio);
- /**
- * Whether or not the progress wave is rendered. If the `waveColor`
- * and `progressColor` are the same color it is not.
- *
- * @type {boolean}
- */
- _this.hasProgressCanvas = params.waveColor != params.progressColor;
- /**
- * @type {number}
- */
- _this.halfPixel = 0.5 / params.pixelRatio;
- /**
- * List of `CanvasEntry` instances.
- *
- * @type {Array}
- */
- _this.canvases = [];
- /**
- * @type {HTMLElement}
- */
- _this.progressWave = null;
- /**
- * Class used to generate entries.
- *
- * @type {function}
- */
- _this.EntryClass = _drawer2.default;
- /**
- * Canvas 2d context attributes.
- *
- * @type {object}
- */
- _this.canvasContextAttributes = params.drawingContextAttributes;
- /**
- * Overlap added between entries to prevent vertical white stripes
- * between `canvas` elements.
- *
- * @type {number}
- */
- _this.overlap = 2 * Math.ceil(params.pixelRatio / 2);
- /**
- * The radius of the wave bars. Makes bars rounded
- *
- * @type {number}
- */
- _this.barRadius = params.barRadius || 0;
- return _this;
- }
- /**
- * Initialize the drawer
- */
- _createClass(MultiCanvas, [{
- key: "init",
- value: function init() {
- this.createWrapper();
- this.createElements();
- }
- /**
- * Create the canvas elements and style them
- *
- */
- }, {
- key: "createElements",
- value: function createElements() {
- this.progressWave = this.wrapper.appendChild(this.style(document.createElement('wave'), {
- position: 'absolute',
- zIndex: 3,
- left: 0,
- top: 0,
- bottom: 0,
- overflow: 'hidden',
- width: '0',
- display: 'none',
- boxSizing: 'border-box',
- borderRightStyle: 'solid',
- pointerEvents: 'none'
- }));
- this.addCanvas();
- this.updateCursor();
- }
- /**
- * Update cursor style
- */
- }, {
- key: "updateCursor",
- value: function updateCursor() {
- this.style(this.progressWave, {
- borderRightWidth: this.params.cursorWidth + 'px',
- borderRightColor: this.params.cursorColor
- });
- }
- /**
- * Adjust to the updated size by adding or removing canvases
- */
- }, {
- key: "updateSize",
- value: function updateSize() {
- var _this2 = this;
- var totalWidth = Math.round(this.width / this.params.pixelRatio);
- var requiredCanvases = Math.ceil(totalWidth / (this.maxCanvasElementWidth + this.overlap)); // add required canvases
- while (this.canvases.length < requiredCanvases) {
- this.addCanvas();
- } // remove older existing canvases, if any
- while (this.canvases.length > requiredCanvases) {
- this.removeCanvas();
- }
- var canvasWidth = this.maxCanvasWidth + this.overlap;
- var lastCanvas = this.canvases.length - 1;
- this.canvases.forEach(function (entry, i) {
- if (i == lastCanvas) {
- canvasWidth = _this2.width - _this2.maxCanvasWidth * lastCanvas;
- }
- _this2.updateDimensions(entry, canvasWidth, _this2.height);
- entry.clearWave();
- });
- }
- /**
- * Add a canvas to the canvas list
- *
- */
- }, {
- key: "addCanvas",
- value: function addCanvas() {
- var entry = new this.EntryClass();
- entry.canvasContextAttributes = this.canvasContextAttributes;
- entry.hasProgressCanvas = this.hasProgressCanvas;
- entry.halfPixel = this.halfPixel;
- var leftOffset = this.maxCanvasElementWidth * this.canvases.length; // wave
- entry.initWave(this.wrapper.appendChild(this.style(document.createElement('canvas'), {
- position: 'absolute',
- zIndex: 2,
- left: leftOffset + 'px',
- top: 0,
- bottom: 0,
- height: '100%',
- pointerEvents: 'none'
- }))); // progress
- if (this.hasProgressCanvas) {
- entry.initProgress(this.progressWave.appendChild(this.style(document.createElement('canvas'), {
- position: 'absolute',
- left: leftOffset + 'px',
- top: 0,
- bottom: 0,
- height: '100%'
- })));
- }
- this.canvases.push(entry);
- }
- /**
- * Pop single canvas from the list
- *
- */
- }, {
- key: "removeCanvas",
- value: function removeCanvas() {
- var lastEntry = this.canvases[this.canvases.length - 1]; // wave
- lastEntry.wave.parentElement.removeChild(lastEntry.wave); // progress
- if (this.hasProgressCanvas) {
- lastEntry.progress.parentElement.removeChild(lastEntry.progress);
- } // cleanup
- if (lastEntry) {
- lastEntry.destroy();
- lastEntry = null;
- }
- this.canvases.pop();
- }
- /**
- * Update the dimensions of a canvas element
- *
- * @param {CanvasEntry} entry Target entry
- * @param {number} width The new width of the element
- * @param {number} height The new height of the element
- */
- }, {
- key: "updateDimensions",
- value: function updateDimensions(entry, width, height) {
- var elementWidth = Math.round(width / this.params.pixelRatio);
- var totalWidth = Math.round(this.width / this.params.pixelRatio); // update canvas dimensions
- entry.updateDimensions(elementWidth, totalWidth, width, height); // style element
- this.style(this.progressWave, {
- display: 'block'
- });
- }
- /**
- * Clear the whole multi-canvas
- */
- }, {
- key: "clearWave",
- value: function clearWave() {
- var _this3 = this;
- util.frame(function () {
- _this3.canvases.forEach(function (entry) {
- return entry.clearWave();
- });
- })();
- }
- /**
- * Draw a waveform with bars
- *
- * @param {number[]|Number.<Array[]>} peaks Can also be an array of arrays
- * for split channel rendering
- * @param {number} channelIndex The index of the current channel. Normally
- * should be 0. Must be an integer.
- * @param {number} start The x-offset of the beginning of the area that
- * should be rendered
- * @param {number} end The x-offset of the end of the area that should be
- * rendered
- * @returns {void}
- */
- }, {
- key: "drawBars",
- value: function drawBars(peaks, channelIndex, start, end) {
- var _this4 = this;
- return this.prepareDraw(peaks, channelIndex, start, end, function (_ref) {
- var absmax = _ref.absmax,
- hasMinVals = _ref.hasMinVals,
- height = _ref.height,
- offsetY = _ref.offsetY,
- halfH = _ref.halfH,
- peaks = _ref.peaks;
- // if drawBars was called within ws.empty we don't pass a start and
- // don't want anything to happen
- if (start === undefined) {
- return;
- } // Skip every other value if there are negatives.
- var peakIndexScale = hasMinVals ? 2 : 1;
- var length = peaks.length / peakIndexScale;
- var bar = _this4.params.barWidth * _this4.params.pixelRatio;
- var gap = _this4.params.barGap === null ? Math.max(_this4.params.pixelRatio, ~~(bar / 2)) : Math.max(_this4.params.pixelRatio, _this4.params.barGap * _this4.params.pixelRatio);
- var step = bar + gap;
- var scale = length / _this4.width;
- var first = start;
- var last = end;
- var i = first;
- for (i; i < last; i += step) {
- var peak = peaks[Math.floor(i * scale * peakIndexScale)] || 0;
- var h = Math.round(peak / absmax * halfH);
- /* in case of silences, allow the user to specify that we
- * always draw *something* (normally a 1px high bar) */
- if (h == 0 && _this4.params.barMinHeight) h = _this4.params.barMinHeight;
- _this4.fillRect(i + _this4.halfPixel, halfH - h + offsetY, bar + _this4.halfPixel, h * 2, _this4.barRadius);
- }
- });
- }
- /**
- * Draw a waveform
- *
- * @param {number[]|Number.<Array[]>} peaks Can also be an array of arrays
- * for split channel rendering
- * @param {number} channelIndex The index of the current channel. Normally
- * should be 0
- * @param {number?} start The x-offset of the beginning of the area that
- * should be rendered (If this isn't set only a flat line is rendered)
- * @param {number?} end The x-offset of the end of the area that should be
- * rendered
- * @returns {void}
- */
- }, {
- key: "drawWave",
- value: function drawWave(peaks, channelIndex, start, end) {
- var _this5 = this;
- return this.prepareDraw(peaks, channelIndex, start, end, function (_ref2) {
- var absmax = _ref2.absmax,
- hasMinVals = _ref2.hasMinVals,
- height = _ref2.height,
- offsetY = _ref2.offsetY,
- halfH = _ref2.halfH,
- peaks = _ref2.peaks,
- channelIndex = _ref2.channelIndex;
- if (!hasMinVals) {
- var reflectedPeaks = [];
- var len = peaks.length;
- var i = 0;
- for (i; i < len; i++) {
- reflectedPeaks[2 * i] = peaks[i];
- reflectedPeaks[2 * i + 1] = -peaks[i];
- }
- peaks = reflectedPeaks;
- } // if drawWave was called within ws.empty we don't pass a start and
- // end and simply want a flat line
- if (start !== undefined) {
- _this5.drawLine(peaks, absmax, halfH, offsetY, start, end, channelIndex);
- } // always draw a median line
- _this5.fillRect(0, halfH + offsetY - _this5.halfPixel, _this5.width, _this5.halfPixel, _this5.barRadius);
- });
- }
- /**
- * Tell the canvas entries to render their portion of the waveform
- *
- * @param {number[]} peaks Peaks data
- * @param {number} absmax Maximum peak value (absolute)
- * @param {number} halfH Half the height of the waveform
- * @param {number} offsetY Offset to the top
- * @param {number} start The x-offset of the beginning of the area that
- * should be rendered
- * @param {number} end The x-offset of the end of the area that
- * should be rendered
- * @param {channelIndex} channelIndex The channel index of the line drawn
- */
- }, {
- key: "drawLine",
- value: function drawLine(peaks, absmax, halfH, offsetY, start, end, channelIndex) {
- var _this6 = this;
- var _ref3 = this.params.splitChannelsOptions.channelColors[channelIndex] || {},
- waveColor = _ref3.waveColor,
- progressColor = _ref3.progressColor;
- this.canvases.forEach(function (entry, i) {
- _this6.setFillStyles(entry, waveColor, progressColor);
- entry.drawLines(peaks, absmax, halfH, offsetY, start, end);
- });
- }
- /**
- * Draw a rectangle on the multi-canvas
- *
- * @param {number} x X-position of the rectangle
- * @param {number} y Y-position of the rectangle
- * @param {number} width Width of the rectangle
- * @param {number} height Height of the rectangle
- * @param {number} radius Radius of the rectangle
- */
- }, {
- key: "fillRect",
- value: function fillRect(x, y, width, height, radius) {
- var startCanvas = Math.floor(x / this.maxCanvasWidth);
- var endCanvas = Math.min(Math.ceil((x + width) / this.maxCanvasWidth) + 1, this.canvases.length);
- var i = startCanvas;
- for (i; i < endCanvas; i++) {
- var entry = this.canvases[i];
- var leftOffset = i * this.maxCanvasWidth;
- var intersection = {
- x1: Math.max(x, i * this.maxCanvasWidth),
- y1: y,
- x2: Math.min(x + width, i * this.maxCanvasWidth + entry.wave.width),
- y2: y + height
- };
- if (intersection.x1 < intersection.x2) {
- this.setFillStyles(entry);
- entry.fillRects(intersection.x1 - leftOffset, intersection.y1, intersection.x2 - intersection.x1, intersection.y2 - intersection.y1, radius);
- }
- }
- }
- /**
- * Returns whether to hide the channel from being drawn based on params.
- *
- * @param {number} channelIndex The index of the current channel.
- * @returns {bool} True to hide the channel, false to draw.
- */
- }, {
- key: "hideChannel",
- value: function hideChannel(channelIndex) {
- return this.params.splitChannels && this.params.splitChannelsOptions.filterChannels.includes(channelIndex);
- }
- /**
- * Performs preparation tasks and calculations which are shared by `drawBars`
- * and `drawWave`
- *
- * @param {number[]|Number.<Array[]>} peaks Can also be an array of arrays for
- * split channel rendering
- * @param {number} channelIndex The index of the current channel. Normally
- * should be 0
- * @param {number?} start The x-offset of the beginning of the area that
- * should be rendered. If this isn't set only a flat line is rendered
- * @param {number?} end The x-offset of the end of the area that should be
- * rendered
- * @param {function} fn The render function to call, e.g. `drawWave`
- * @param {number} drawIndex The index of the current channel after filtering.
- * @returns {void}
- */
- }, {
- key: "prepareDraw",
- value: function prepareDraw(peaks, channelIndex, start, end, fn, drawIndex) {
- var _this7 = this;
- return util.frame(function () {
- // Split channels and call this function with the channelIndex set
- if (peaks[0] instanceof Array) {
- var channels = peaks;
- if (_this7.params.splitChannels) {
- var filteredChannels = channels.filter(function (c, i) {
- return !_this7.hideChannel(i);
- });
- if (!_this7.params.splitChannelsOptions.overlay) {
- _this7.setHeight(Math.max(filteredChannels.length, 1) * _this7.params.height * _this7.params.pixelRatio);
- }
- return channels.forEach(function (channelPeaks, i) {
- return _this7.prepareDraw(channelPeaks, i, start, end, fn, filteredChannels.indexOf(channelPeaks));
- });
- }
- peaks = channels[0];
- } // Return and do not draw channel peaks if hidden.
- if (_this7.hideChannel(channelIndex)) {
- return;
- } // calculate maximum modulation value, either from the barHeight
- // parameter or if normalize=true from the largest value in the peak
- // set
- var absmax = 1 / _this7.params.barHeight;
- if (_this7.params.normalize) {
- var max = util.max(peaks);
- var min = util.min(peaks);
- absmax = -min > max ? -min : max;
- } // Bar wave draws the bottom only as a reflection of the top,
- // so we don't need negative values
- var hasMinVals = [].some.call(peaks, function (val) {
- return val < 0;
- });
- var height = _this7.params.height * _this7.params.pixelRatio;
- var offsetY = height * drawIndex || 0;
- var halfH = height / 2;
- return fn({
- absmax: absmax,
- hasMinVals: hasMinVals,
- height: height,
- offsetY: offsetY,
- halfH: halfH,
- peaks: peaks,
- channelIndex: channelIndex
- });
- })();
- }
- /**
- * Set the fill styles for a certain entry (wave and progress)
- *
- * @param {CanvasEntry} entry Target entry
- * @param {string} waveColor Wave color to draw this entry
- * @param {string} progressColor Progress color to draw this entry
- */
- }, {
- key: "setFillStyles",
- value: function setFillStyles(entry) {
- var waveColor = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.params.waveColor;
- var progressColor = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : this.params.progressColor;
- entry.setFillStyles(waveColor, progressColor);
- }
- /**
- * Return image data of the multi-canvas
- *
- * When using a `type` of `'blob'`, this will return a `Promise`.
- *
- * @param {string} format='image/png' An optional value of a format type.
- * @param {number} quality=0.92 An optional value between 0 and 1.
- * @param {string} type='dataURL' Either 'dataURL' or 'blob'.
- * @return {string|string[]|Promise} When using the default `'dataURL'`
- * `type` this returns a single data URL or an array of data URLs,
- * one for each canvas. When using the `'blob'` `type` this returns a
- * `Promise` that resolves with an array of `Blob` instances, one for each
- * canvas.
- */
- }, {
- key: "getImage",
- value: function getImage(format, quality, type) {
- if (type === 'blob') {
- return Promise.all(this.canvases.map(function (entry) {
- return entry.getImage(format, quality, type);
- }));
- } else if (type === 'dataURL') {
- var images = this.canvases.map(function (entry) {
- return entry.getImage(format, quality, type);
- });
- return images.length > 1 ? images : images[0];
- }
- }
- /**
- * Render the new progress
- *
- * @param {number} position X-offset of progress position in pixels
- */
- }, {
- key: "updateProgress",
- value: function updateProgress(position) {
- this.style(this.progressWave, {
- width: position + 'px'
- });
- }
- }]);
- return MultiCanvas;
- }(_drawer.default);
- exports.default = MultiCanvas;
- module.exports = exports.default;
- /***/ }),
- /***/ "./src/mediaelement-webaudio.js":
- /*!**************************************!*\
- !*** ./src/mediaelement-webaudio.js ***!
- \**************************************/
- /*! no static exports found */
- /***/ (function(module, exports, __webpack_require__) {
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
- var _mediaelement = _interopRequireDefault(__webpack_require__(/*! ./mediaelement */ "./src/mediaelement.js"));
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
- 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); }
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
- 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); } }
- function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
- 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); }
- function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; }
- 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); }
- function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
- 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); }; }
- function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
- function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
- 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; } }
- function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
- /**
- * MediaElementWebAudio backend: load audio via an HTML5 audio tag, but playback with the WebAudio API.
- * The advantage here is that the html5 <audio> tag can perform range requests on the server and not
- * buffer the entire file in one request, and you still get the filtering and scripting functionality
- * of the webaudio API.
- * Note that in order to use range requests and prevent buffering, you must provide peak data.
- *
- * @since 3.2.0
- */
- var MediaElementWebAudio = /*#__PURE__*/function (_MediaElement) {
- _inherits(MediaElementWebAudio, _MediaElement);
- var _super = _createSuper(MediaElementWebAudio);
- /**
- * Construct the backend
- *
- * @param {WavesurferParams} params Wavesurfer parameters
- */
- function MediaElementWebAudio(params) {
- var _this;
- _classCallCheck(this, MediaElementWebAudio);
- _this = _super.call(this, params);
- /** @private */
- _this.params = params;
- /** @private */
- _this.sourceMediaElement = null;
- return _this;
- }
- /**
- * Initialise the backend, called in `wavesurfer.createBackend()`
- */
- _createClass(MediaElementWebAudio, [{
- key: "init",
- value: function init() {
- this.setPlaybackRate(this.params.audioRate);
- this.createTimer();
- this.createVolumeNode();
- this.createScriptNode();
- this.createAnalyserNode();
- }
- /**
- * Private method called by both `load` (from url)
- * and `loadElt` (existing media element) methods.
- *
- * @param {HTMLMediaElement} media HTML5 Audio or Video element
- * @param {number[]|Number.<Array[]>} peaks Array of peak data
- * @param {string} preload HTML 5 preload attribute value
- * @private
- */
- }, {
- key: "_load",
- value: function _load(media, peaks, preload) {
- _get(_getPrototypeOf(MediaElementWebAudio.prototype), "_load", this).call(this, media, peaks, preload);
- this.createMediaElementSource(media);
- }
- /**
- * Create MediaElementSource node
- *
- * @since 3.2.0
- * @param {HTMLMediaElement} mediaElement HTML5 Audio to load
- */
- }, {
- key: "createMediaElementSource",
- value: function createMediaElementSource(mediaElement) {
- this.sourceMediaElement = this.ac.createMediaElementSource(mediaElement);
- this.sourceMediaElement.connect(this.analyser);
- }
- }, {
- key: "play",
- value: function play(start, end) {
- this.resumeAudioContext();
- return _get(_getPrototypeOf(MediaElementWebAudio.prototype), "play", this).call(this, start, end);
- }
- /**
- * This is called when wavesurfer is destroyed
- *
- */
- }, {
- key: "destroy",
- value: function destroy() {
- _get(_getPrototypeOf(MediaElementWebAudio.prototype), "destroy", this).call(this);
- this.destroyWebAudio();
- }
- }]);
- return MediaElementWebAudio;
- }(_mediaelement.default);
- exports.default = MediaElementWebAudio;
- module.exports = exports.default;
- /***/ }),
- /***/ "./src/mediaelement.js":
- /*!*****************************!*\
- !*** ./src/mediaelement.js ***!
- \*****************************/
- /*! no static exports found */
- /***/ (function(module, exports, __webpack_require__) {
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
- var _webaudio = _interopRequireDefault(__webpack_require__(/*! ./webaudio */ "./src/webaudio.js"));
- var util = _interopRequireWildcard(__webpack_require__(/*! ./util */ "./src/util/index.js"));
- function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; }
- 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; }
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
- 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); }
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
- 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); } }
- function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
- 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); }
- function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; }
- 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); }
- function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
- 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); }; }
- function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
- function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
- 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; } }
- function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
- /**
- * MediaElement backend
- */
- var MediaElement = /*#__PURE__*/function (_WebAudio) {
- _inherits(MediaElement, _WebAudio);
- var _super = _createSuper(MediaElement);
- /**
- * Construct the backend
- *
- * @param {WavesurferParams} params Wavesurfer parameters
- */
- function MediaElement(params) {
- var _this;
- _classCallCheck(this, MediaElement);
- _this = _super.call(this, params);
- /** @private */
- _this.params = params;
- /**
- * Initially a dummy media element to catch errors. Once `_load` is
- * called, this will contain the actual `HTMLMediaElement`.
- * @private
- */
- _this.media = {
- currentTime: 0,
- duration: 0,
- paused: true,
- playbackRate: 1,
- play: function play() {},
- pause: function pause() {},
- volume: 0
- };
- /** @private */
- _this.mediaType = params.mediaType.toLowerCase();
- /** @private */
- _this.elementPosition = params.elementPosition;
- /** @private */
- _this.peaks = null;
- /** @private */
- _this.playbackRate = 1;
- /** @private */
- _this.volume = 1;
- /** @private */
- _this.isMuted = false;
- /** @private */
- _this.buffer = null;
- /** @private */
- _this.onPlayEnd = null;
- /** @private */
- _this.mediaListeners = {};
- return _this;
- }
- /**
- * Initialise the backend, called in `wavesurfer.createBackend()`
- */
- _createClass(MediaElement, [{
- key: "init",
- value: function init() {
- this.setPlaybackRate(this.params.audioRate);
- this.createTimer();
- }
- /**
- * Attach event listeners to media element.
- */
- }, {
- key: "_setupMediaListeners",
- value: function _setupMediaListeners() {
- var _this2 = this;
- this.mediaListeners.error = function () {
- _this2.fireEvent('error', 'Error loading media element');
- };
- this.mediaListeners.canplay = function () {
- _this2.fireEvent('canplay');
- };
- this.mediaListeners.ended = function () {
- _this2.fireEvent('finish');
- }; // listen to and relay play, pause and seeked events to enable
- // playback control from the external media element
- this.mediaListeners.play = function () {
- _this2.fireEvent('play');
- };
- this.mediaListeners.pause = function () {
- _this2.fireEvent('pause');
- };
- this.mediaListeners.seeked = function (event) {
- _this2.fireEvent('seek');
- };
- this.mediaListeners.volumechange = function (event) {
- _this2.isMuted = _this2.media.muted;
- if (_this2.isMuted) {
- _this2.volume = 0;
- } else {
- _this2.volume = _this2.media.volume;
- }
- _this2.fireEvent('volume');
- }; // reset event listeners
- Object.keys(this.mediaListeners).forEach(function (id) {
- _this2.media.removeEventListener(id, _this2.mediaListeners[id]);
- _this2.media.addEventListener(id, _this2.mediaListeners[id]);
- });
- }
- /**
- * Create a timer to provide a more precise `audioprocess` event.
- */
- }, {
- key: "createTimer",
- value: function createTimer() {
- var _this3 = this;
- var onAudioProcess = function onAudioProcess() {
- if (_this3.isPaused()) {
- return;
- }
- _this3.fireEvent('audioprocess', _this3.getCurrentTime()); // Call again in the next frame
- util.frame(onAudioProcess)();
- };
- this.on('play', onAudioProcess); // Update the progress one more time to prevent it from being stuck in
- // case of lower framerates
- this.on('pause', function () {
- _this3.fireEvent('audioprocess', _this3.getCurrentTime());
- });
- }
- /**
- * Create media element with url as its source,
- * and append to container element.
- *
- * @param {string} url Path to media file
- * @param {HTMLElement} container HTML element
- * @param {number[]|Number.<Array[]>} peaks Array of peak data
- * @param {string} preload HTML 5 preload attribute value
- * @throws Will throw an error if the `url` argument is not a valid media
- * element.
- */
- }, {
- key: "load",
- value: function load(url, container, peaks, preload) {
- var media = document.createElement(this.mediaType);
- media.controls = this.params.mediaControls;
- media.autoplay = this.params.autoplay || false;
- media.preload = preload == null ? 'auto' : preload;
- media.src = url;
- media.style.width = '100%';
- var prevMedia = container.querySelector(this.mediaType);
- if (prevMedia) {
- container.removeChild(prevMedia);
- }
- container.appendChild(media);
- this._load(media, peaks, preload);
- }
- /**
- * Load existing media element.
- *
- * @param {HTMLMediaElement} elt HTML5 Audio or Video element
- * @param {number[]|Number.<Array[]>} peaks Array of peak data
- */
- }, {
- key: "loadElt",
- value: function loadElt(elt, peaks) {
- elt.controls = this.params.mediaControls;
- elt.autoplay = this.params.autoplay || false;
- this._load(elt, peaks, elt.preload);
- }
- /**
- * Method called by both `load` (from url)
- * and `loadElt` (existing media element) methods.
- *
- * @param {HTMLMediaElement} media HTML5 Audio or Video element
- * @param {number[]|Number.<Array[]>} peaks Array of peak data
- * @param {string} preload HTML 5 preload attribute value
- * @throws Will throw an error if the `media` argument is not a valid media
- * element.
- * @private
- */
- }, {
- key: "_load",
- value: function _load(media, peaks, preload) {
- // verify media element is valid
- if (!(media instanceof HTMLMediaElement) || typeof media.addEventListener === 'undefined') {
- throw new Error('media parameter is not a valid media element');
- } // load must be called manually on iOS, otherwise peaks won't draw
- // until a user interaction triggers load --> 'ready' event
- //
- // note that we avoid calling media.load here when given peaks and preload == 'none'
- // as this almost always triggers some browser fetch of the media.
- if (typeof media.load == 'function' && !(peaks && preload == 'none')) {
- // Resets the media element and restarts the media resource. Any
- // pending events are discarded. How much media data is fetched is
- // still affected by the preload attribute.
- media.load();
- }
- this.media = media;
- this._setupMediaListeners();
- this.peaks = peaks;
- this.onPlayEnd = null;
- this.buffer = null;
- this.isMuted = media.muted;
- this.setPlaybackRate(this.playbackRate);
- this.setVolume(this.volume);
- }
- /**
- * Used by `wavesurfer.isPlaying()` and `wavesurfer.playPause()`
- *
- * @return {boolean} Media paused or not
- */
- }, {
- key: "isPaused",
- value: function isPaused() {
- return !this.media || this.media.paused;
- }
- /**
- * Used by `wavesurfer.getDuration()`
- *
- * @return {number} Duration
- */
- }, {
- key: "getDuration",
- value: function getDuration() {
- if (this.explicitDuration) {
- return this.explicitDuration;
- }
- var duration = (this.buffer || this.media).duration;
- if (duration >= Infinity) {
- // streaming audio
- duration = this.media.seekable.end(0);
- }
- return duration;
- }
- /**
- * Returns the current time in seconds relative to the audio-clip's
- * duration.
- *
- * @return {number} Current time
- */
- }, {
- key: "getCurrentTime",
- value: function getCurrentTime() {
- return this.media && this.media.currentTime;
- }
- /**
- * Get the position from 0 to 1
- *
- * @return {number} Current position
- */
- }, {
- key: "getPlayedPercents",
- value: function getPlayedPercents() {
- return this.getCurrentTime() / this.getDuration() || 0;
- }
- /**
- * Get the audio source playback rate.
- *
- * @return {number} Playback rate
- */
- }, {
- key: "getPlaybackRate",
- value: function getPlaybackRate() {
- return this.playbackRate || this.media.playbackRate;
- }
- /**
- * Set the audio source playback rate.
- *
- * @param {number} value Playback rate
- */
- }, {
- key: "setPlaybackRate",
- value: function setPlaybackRate(value) {
- this.playbackRate = value || 1;
- this.media.playbackRate = this.playbackRate;
- }
- /**
- * Used by `wavesurfer.seekTo()`
- *
- * @param {number} start Position to start at in seconds
- */
- }, {
- key: "seekTo",
- value: function seekTo(start) {
- if (start != null) {
- this.media.currentTime = start;
- }
- this.clearPlayEnd();
- }
- /**
- * Plays the loaded audio region.
- *
- * @param {number} start Start offset in seconds, relative to the beginning
- * of a clip.
- * @param {number} end When to stop, relative to the beginning of a clip.
- * @emits MediaElement#play
- * @return {Promise} Result
- */
- }, {
- key: "play",
- value: function play(start, end) {
- this.seekTo(start);
- var promise = this.media.play();
- end && this.setPlayEnd(end);
- return promise;
- }
- /**
- * Pauses the loaded audio.
- *
- * @emits MediaElement#pause
- * @return {Promise} Result
- */
- }, {
- key: "pause",
- value: function pause() {
- var promise;
- if (this.media) {
- promise = this.media.pause();
- }
- this.clearPlayEnd();
- return promise;
- }
- /**
- * Set the play end
- *
- * @param {number} end Where to end
- */
- }, {
- key: "setPlayEnd",
- value: function setPlayEnd(end) {
- var _this4 = this;
- this.clearPlayEnd();
- this._onPlayEnd = function (time) {
- if (time >= end) {
- _this4.pause();
- _this4.seekTo(end);
- }
- };
- this.on('audioprocess', this._onPlayEnd);
- }
- /** @private */
- }, {
- key: "clearPlayEnd",
- value: function clearPlayEnd() {
- if (this._onPlayEnd) {
- this.un('audioprocess', this._onPlayEnd);
- this._onPlayEnd = null;
- }
- }
- /**
- * Compute the max and min value of the waveform when broken into
- * <length> subranges.
- *
- * @param {number} length How many subranges to break the waveform into.
- * @param {number} first First sample in the required range.
- * @param {number} last Last sample in the required range.
- * @return {number[]|Number.<Array[]>} Array of 2*<length> peaks or array of
- * arrays of peaks consisting of (max, min) values for each subrange.
- */
- }, {
- key: "getPeaks",
- value: function getPeaks(length, first, last) {
- if (this.buffer) {
- return _get(_getPrototypeOf(MediaElement.prototype), "getPeaks", this).call(this, length, first, last);
- }
- return this.peaks || [];
- }
- /**
- * Set the sink id for the media player
- *
- * @param {string} deviceId String value representing audio device id.
- * @returns {Promise} A Promise that resolves to `undefined` when there
- * are no errors.
- */
- }, {
- key: "setSinkId",
- value: function setSinkId(deviceId) {
- if (deviceId) {
- if (!this.media.setSinkId) {
- return Promise.reject(new Error('setSinkId is not supported in your browser'));
- }
- return this.media.setSinkId(deviceId);
- }
- return Promise.reject(new Error('Invalid deviceId: ' + deviceId));
- }
- /**
- * Get the current volume
- *
- * @return {number} value A floating point value between 0 and 1.
- */
- }, {
- key: "getVolume",
- value: function getVolume() {
- return this.volume;
- }
- /**
- * Set the audio volume
- *
- * @param {number} value A floating point value between 0 and 1.
- */
- }, {
- key: "setVolume",
- value: function setVolume(value) {
- this.volume = value; // no need to change when it's already at that volume
- if (this.media.volume !== this.volume) {
- this.media.volume = this.volume;
- }
- }
- /**
- * Enable or disable muted audio
- *
- * @since 4.0.0
- * @param {boolean} muted Specify `true` to mute audio.
- */
- }, {
- key: "setMute",
- value: function setMute(muted) {
- // This causes a volume change to be emitted too through the
- // volumechange event listener.
- this.isMuted = this.media.muted = muted;
- }
- /**
- * This is called when wavesurfer is destroyed
- *
- */
- }, {
- key: "destroy",
- value: function destroy() {
- var _this5 = this;
- this.pause();
- this.unAll();
- this.destroyed = true; // cleanup media event listeners
- Object.keys(this.mediaListeners).forEach(function (id) {
- if (_this5.media) {
- _this5.media.removeEventListener(id, _this5.mediaListeners[id]);
- }
- });
- if (this.params.removeMediaElementOnDestroy && this.media && this.media.parentNode) {
- this.media.parentNode.removeChild(this.media);
- }
- this.media = null;
- }
- }]);
- return MediaElement;
- }(_webaudio.default);
- exports.default = MediaElement;
- module.exports = exports.default;
- /***/ }),
- /***/ "./src/peakcache.js":
- /*!**************************!*\
- !*** ./src/peakcache.js ***!
- \**************************/
- /*! no static exports found */
- /***/ (function(module, exports, __webpack_require__) {
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
- 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); } }
- function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
- /**
- * Caches the decoded peaks data to improve rendering speed for large audio
- *
- * Is used if the option parameter `partialRender` is set to `true`
- */
- var PeakCache = /*#__PURE__*/function () {
- /**
- * Instantiate cache
- */
- function PeakCache() {
- _classCallCheck(this, PeakCache);
- this.clearPeakCache();
- }
- /**
- * Empty the cache
- */
- _createClass(PeakCache, [{
- key: "clearPeakCache",
- value: function clearPeakCache() {
- /**
- * Flat array with entries that are always in pairs to mark the
- * beginning and end of each subrange. This is a convenience so we can
- * iterate over the pairs for easy set difference operations.
- * @private
- */
- this.peakCacheRanges = [];
- /**
- * Length of the entire cachable region, used for resetting the cache
- * when this changes (zoom events, for instance).
- * @private
- */
- this.peakCacheLength = -1;
- }
- /**
- * Add a range of peaks to the cache
- *
- * @param {number} length The length of the range
- * @param {number} start The x offset of the start of the range
- * @param {number} end The x offset of the end of the range
- * @return {Number.<Array[]>} Array with arrays of numbers
- */
- }, {
- key: "addRangeToPeakCache",
- value: function addRangeToPeakCache(length, start, end) {
- if (length != this.peakCacheLength) {
- this.clearPeakCache();
- this.peakCacheLength = length;
- } // Return ranges that weren't in the cache before the call.
- var uncachedRanges = [];
- var i = 0; // Skip ranges before the current start.
- while (i < this.peakCacheRanges.length && this.peakCacheRanges[i] < start) {
- i++;
- } // If |i| is even, |start| falls after an existing range. Otherwise,
- // |start| falls between an existing range, and the uncached region
- // starts when we encounter the next node in |peakCacheRanges| or
- // |end|, whichever comes first.
- if (i % 2 == 0) {
- uncachedRanges.push(start);
- }
- while (i < this.peakCacheRanges.length && this.peakCacheRanges[i] <= end) {
- uncachedRanges.push(this.peakCacheRanges[i]);
- i++;
- } // If |i| is even, |end| is after all existing ranges.
- if (i % 2 == 0) {
- uncachedRanges.push(end);
- } // Filter out the 0-length ranges.
- uncachedRanges = uncachedRanges.filter(function (item, pos, arr) {
- if (pos == 0) {
- return item != arr[pos + 1];
- } else if (pos == arr.length - 1) {
- return item != arr[pos - 1];
- }
- return item != arr[pos - 1] && item != arr[pos + 1];
- }); // Merge the two ranges together, uncachedRanges will either contain
- // wholly new points, or duplicates of points in peakCacheRanges. If
- // duplicates are detected, remove both and extend the range.
- this.peakCacheRanges = this.peakCacheRanges.concat(uncachedRanges);
- this.peakCacheRanges = this.peakCacheRanges.sort(function (a, b) {
- return a - b;
- }).filter(function (item, pos, arr) {
- if (pos == 0) {
- return item != arr[pos + 1];
- } else if (pos == arr.length - 1) {
- return item != arr[pos - 1];
- }
- return item != arr[pos - 1] && item != arr[pos + 1];
- }); // Push the uncached ranges into an array of arrays for ease of
- // iteration in the functions that call this.
- var uncachedRangePairs = [];
- for (i = 0; i < uncachedRanges.length; i += 2) {
- uncachedRangePairs.push([uncachedRanges[i], uncachedRanges[i + 1]]);
- }
- return uncachedRangePairs;
- }
- /**
- * For testing
- *
- * @return {Number.<Array[]>} Array with arrays of numbers
- */
- }, {
- key: "getCacheRanges",
- value: function getCacheRanges() {
- var peakCacheRangePairs = [];
- var i;
- for (i = 0; i < this.peakCacheRanges.length; i += 2) {
- peakCacheRangePairs.push([this.peakCacheRanges[i], this.peakCacheRanges[i + 1]]);
- }
- return peakCacheRangePairs;
- }
- }]);
- return PeakCache;
- }();
- exports.default = PeakCache;
- module.exports = exports.default;
- /***/ }),
- /***/ "./src/util/clamp.js":
- /*!***************************!*\
- !*** ./src/util/clamp.js ***!
- \***************************/
- /*! no static exports found */
- /***/ (function(module, exports, __webpack_require__) {
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = clamp;
- /**
- * Returns a number limited to the given range.
- *
- * @param {number} val The number to be limited to a range
- * @param {number} min The lower boundary of the limit range
- * @param {number} max The upper boundary of the limit range
- * @returns {number} A number in the range [min, max]
- */
- function clamp(val, min, max) {
- return Math.min(Math.max(min, val), max);
- }
- module.exports = exports.default;
- /***/ }),
- /***/ "./src/util/fetch.js":
- /*!***************************!*\
- !*** ./src/util/fetch.js ***!
- \***************************/
- /*! no static exports found */
- /***/ (function(module, exports, __webpack_require__) {
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = fetchFile;
- var _observer = _interopRequireDefault(__webpack_require__(/*! ./observer */ "./src/util/observer.js"));
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
- 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); } }
- function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
- var ProgressHandler = /*#__PURE__*/function () {
- /**
- * Instantiate ProgressHandler
- *
- * @param {Observer} instance The `fetchFile` observer instance.
- * @param {Number} contentLength Content length.
- * @param {Response} response Response object.
- */
- function ProgressHandler(instance, contentLength, response) {
- _classCallCheck(this, ProgressHandler);
- this.instance = instance;
- this.instance._reader = response.body.getReader();
- this.total = parseInt(contentLength, 10);
- this.loaded = 0;
- }
- /**
- * A method that is called once, immediately after the `ReadableStream``
- * is constructed.
- *
- * @param {ReadableStreamDefaultController} controller Controller instance
- * used to control the stream.
- */
- _createClass(ProgressHandler, [{
- key: "start",
- value: function start(controller) {
- var _this = this;
- var read = function read() {
- // instance._reader.read() returns a promise that resolves
- // when a value has been received
- _this.instance._reader.read().then(function (_ref) {
- var done = _ref.done,
- value = _ref.value;
- // result objects contain two properties:
- // done - true if the stream has already given you all its data.
- // value - some data. Always undefined when done is true.
- if (done) {
- // ensure onProgress called when content-length=0
- if (_this.total === 0) {
- _this.instance.onProgress.call(_this.instance, {
- loaded: _this.loaded,
- total: _this.total,
- lengthComputable: false
- });
- } // no more data needs to be consumed, close the stream
- controller.close();
- return;
- }
- _this.loaded += value.byteLength;
- _this.instance.onProgress.call(_this.instance, {
- loaded: _this.loaded,
- total: _this.total,
- lengthComputable: !(_this.total === 0)
- }); // enqueue the next data chunk into our target stream
- controller.enqueue(value);
- read();
- }).catch(function (error) {
- controller.error(error);
- });
- };
- read();
- }
- }]);
- return ProgressHandler;
- }();
- /**
- * Load a file using `fetch`.
- *
- * @param {object} options Request options to use. See example below.
- * @returns {Observer} Observer instance
- * @example
- * // default options
- * let options = {
- * url: undefined,
- * method: 'GET',
- * mode: 'cors',
- * credentials: 'same-origin',
- * cache: 'default',
- * responseType: 'json',
- * requestHeaders: [],
- * redirect: 'follow',
- * referrer: 'client'
- * };
- *
- * // override some options
- * options.url = '../media/demo.wav';
- * // available types: 'arraybuffer', 'blob', 'json' or 'text'
- * options.responseType = 'arraybuffer';
- *
- * // make fetch call
- * let request = util.fetchFile(options);
- *
- * // listen for events
- * request.on('progress', e => {
- * console.log('progress', e);
- * });
- *
- * request.on('success', data => {
- * console.log('success!', data);
- * });
- *
- * request.on('error', e => {
- * console.warn('fetchFile error: ', e);
- * });
- */
- function fetchFile(options) {
- if (!options) {
- throw new Error('fetch options missing');
- } else if (!options.url) {
- throw new Error('fetch url missing');
- }
- var instance = new _observer.default();
- var fetchHeaders = new Headers();
- var fetchRequest = new Request(options.url); // add ability to abort
- instance.controller = new AbortController(); // check if headers have to be added
- if (options && options.requestHeaders) {
- // add custom request headers
- options.requestHeaders.forEach(function (header) {
- fetchHeaders.append(header.key, header.value);
- });
- } // parse fetch options
- var responseType = options.responseType || 'json';
- var fetchOptions = {
- method: options.method || 'GET',
- headers: fetchHeaders,
- mode: options.mode || 'cors',
- credentials: options.credentials || 'same-origin',
- cache: options.cache || 'default',
- redirect: options.redirect || 'follow',
- referrer: options.referrer || 'client',
- signal: instance.controller.signal
- };
- fetch(fetchRequest, fetchOptions).then(function (response) {
- // store response reference
- instance.response = response;
- var progressAvailable = true;
- if (!response.body) {
- // ReadableStream is not yet supported in this browser
- // see https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream
- progressAvailable = false;
- } // Server must send CORS header "Access-Control-Expose-Headers: content-length"
- var contentLength = response.headers.get('content-length');
- if (contentLength === null) {
- // Content-Length server response header missing.
- // Don't evaluate download progress if we can't compare against a total size
- // see https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#Access-Control-Expose-Headers
- progressAvailable = false;
- }
- if (!progressAvailable) {
- // not able to check download progress so skip it
- return response;
- } // fire progress event when during load
- instance.onProgress = function (e) {
- instance.fireEvent('progress', e);
- };
- return new Response(new ReadableStream(new ProgressHandler(instance, contentLength, response)), fetchOptions);
- }).then(function (response) {
- var errMsg;
- if (response.ok) {
- switch (responseType) {
- case 'arraybuffer':
- return response.arrayBuffer();
- case 'json':
- return response.json();
- case 'blob':
- return response.blob();
- case 'text':
- return response.text();
- default:
- errMsg = 'Unknown responseType: ' + responseType;
- break;
- }
- }
- if (!errMsg) {
- errMsg = 'HTTP error status: ' + response.status;
- }
- throw new Error(errMsg);
- }).then(function (response) {
- instance.fireEvent('success', response);
- }).catch(function (error) {
- instance.fireEvent('error', error);
- }); // return the fetch request
- instance.fetchRequest = fetchRequest;
- return instance;
- }
- module.exports = exports.default;
- /***/ }),
- /***/ "./src/util/frame.js":
- /*!***************************!*\
- !*** ./src/util/frame.js ***!
- \***************************/
- /*! no static exports found */
- /***/ (function(module, exports, __webpack_require__) {
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = frame;
- var _requestAnimationFrame = _interopRequireDefault(__webpack_require__(/*! ./request-animation-frame */ "./src/util/request-animation-frame.js"));
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
- /**
- * Create a function which will be called at the next requestAnimationFrame
- * cycle
- *
- * @param {function} func The function to call
- *
- * @return {func} The function wrapped within a requestAnimationFrame
- */
- function frame(func) {
- return function () {
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
- args[_key] = arguments[_key];
- }
- return (0, _requestAnimationFrame.default)(function () {
- return func.apply(void 0, args);
- });
- };
- }
- module.exports = exports.default;
- /***/ }),
- /***/ "./src/util/get-id.js":
- /*!****************************!*\
- !*** ./src/util/get-id.js ***!
- \****************************/
- /*! no static exports found */
- /***/ (function(module, exports, __webpack_require__) {
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = getId;
- /**
- * Get a random prefixed ID
- *
- * @param {String} prefix Prefix to use. Default is `'wavesurfer_'`.
- * @returns {String} Random prefixed ID
- * @example
- * console.log(getId()); // logs 'wavesurfer_b5pors4ru6g'
- *
- * let prefix = 'foo-';
- * console.log(getId(prefix)); // logs 'foo-b5pors4ru6g'
- */
- function getId(prefix) {
- if (prefix === undefined) {
- prefix = 'wavesurfer_';
- }
- return prefix + Math.random().toString(32).substring(2);
- }
- module.exports = exports.default;
- /***/ }),
- /***/ "./src/util/index.js":
- /*!***************************!*\
- !*** ./src/util/index.js ***!
- \***************************/
- /*! no static exports found */
- /***/ (function(module, exports, __webpack_require__) {
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- Object.defineProperty(exports, "getId", {
- enumerable: true,
- get: function get() {
- return _getId.default;
- }
- });
- Object.defineProperty(exports, "max", {
- enumerable: true,
- get: function get() {
- return _max.default;
- }
- });
- Object.defineProperty(exports, "min", {
- enumerable: true,
- get: function get() {
- return _min.default;
- }
- });
- Object.defineProperty(exports, "Observer", {
- enumerable: true,
- get: function get() {
- return _observer.default;
- }
- });
- Object.defineProperty(exports, "style", {
- enumerable: true,
- get: function get() {
- return _style.default;
- }
- });
- Object.defineProperty(exports, "requestAnimationFrame", {
- enumerable: true,
- get: function get() {
- return _requestAnimationFrame.default;
- }
- });
- Object.defineProperty(exports, "frame", {
- enumerable: true,
- get: function get() {
- return _frame.default;
- }
- });
- Object.defineProperty(exports, "debounce", {
- enumerable: true,
- get: function get() {
- return _debounce.default;
- }
- });
- Object.defineProperty(exports, "preventClick", {
- enumerable: true,
- get: function get() {
- return _preventClick.default;
- }
- });
- Object.defineProperty(exports, "fetchFile", {
- enumerable: true,
- get: function get() {
- return _fetch.default;
- }
- });
- Object.defineProperty(exports, "clamp", {
- enumerable: true,
- get: function get() {
- return _clamp.default;
- }
- });
- var _getId = _interopRequireDefault(__webpack_require__(/*! ./get-id */ "./src/util/get-id.js"));
- var _max = _interopRequireDefault(__webpack_require__(/*! ./max */ "./src/util/max.js"));
- var _min = _interopRequireDefault(__webpack_require__(/*! ./min */ "./src/util/min.js"));
- var _observer = _interopRequireDefault(__webpack_require__(/*! ./observer */ "./src/util/observer.js"));
- var _style = _interopRequireDefault(__webpack_require__(/*! ./style */ "./src/util/style.js"));
- var _requestAnimationFrame = _interopRequireDefault(__webpack_require__(/*! ./request-animation-frame */ "./src/util/request-animation-frame.js"));
- var _frame = _interopRequireDefault(__webpack_require__(/*! ./frame */ "./src/util/frame.js"));
- var _debounce = _interopRequireDefault(__webpack_require__(/*! debounce */ "./node_modules/debounce/index.js"));
- var _preventClick = _interopRequireDefault(__webpack_require__(/*! ./prevent-click */ "./src/util/prevent-click.js"));
- var _fetch = _interopRequireDefault(__webpack_require__(/*! ./fetch */ "./src/util/fetch.js"));
- var _clamp = _interopRequireDefault(__webpack_require__(/*! ./clamp */ "./src/util/clamp.js"));
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
- /***/ }),
- /***/ "./src/util/max.js":
- /*!*************************!*\
- !*** ./src/util/max.js ***!
- \*************************/
- /*! no static exports found */
- /***/ (function(module, exports, __webpack_require__) {
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = max;
- /**
- * Get the largest value
- *
- * @param {Array} values Array of numbers
- * @returns {Number} Largest number found
- * @example console.log(max([1, 2, 3])); // logs 3
- */
- function max(values) {
- var largest = -Infinity;
- Object.keys(values).forEach(function (i) {
- if (values[i] > largest) {
- largest = values[i];
- }
- });
- return largest;
- }
- module.exports = exports.default;
- /***/ }),
- /***/ "./src/util/min.js":
- /*!*************************!*\
- !*** ./src/util/min.js ***!
- \*************************/
- /*! no static exports found */
- /***/ (function(module, exports, __webpack_require__) {
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = min;
- /**
- * Get the smallest value
- *
- * @param {Array} values Array of numbers
- * @returns {Number} Smallest number found
- * @example console.log(min([1, 2, 3])); // logs 1
- */
- function min(values) {
- var smallest = Number(Infinity);
- Object.keys(values).forEach(function (i) {
- if (values[i] < smallest) {
- smallest = values[i];
- }
- });
- return smallest;
- }
- module.exports = exports.default;
- /***/ }),
- /***/ "./src/util/observer.js":
- /*!******************************!*\
- !*** ./src/util/observer.js ***!
- \******************************/
- /*! no static exports found */
- /***/ (function(module, exports, __webpack_require__) {
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
- 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); } }
- function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
- /**
- * @typedef {Object} ListenerDescriptor
- * @property {string} name The name of the event
- * @property {function} callback The callback
- * @property {function} un The function to call to remove the listener
- */
- /**
- * Observer class
- */
- var Observer = /*#__PURE__*/function () {
- /**
- * Instantiate Observer
- */
- function Observer() {
- _classCallCheck(this, Observer);
- /**
- * @private
- * @todo Initialise the handlers here already and remove the conditional
- * assignment in `on()`
- */
- this._disabledEventEmissions = [];
- this.handlers = null;
- }
- /**
- * Attach a handler function for an event.
- *
- * @param {string} event Name of the event to listen to
- * @param {function} fn The callback to trigger when the event is fired
- * @return {ListenerDescriptor} The event descriptor
- */
- _createClass(Observer, [{
- key: "on",
- value: function on(event, fn) {
- var _this = this;
- if (!this.handlers) {
- this.handlers = {};
- }
- var handlers = this.handlers[event];
- if (!handlers) {
- handlers = this.handlers[event] = [];
- }
- handlers.push(fn); // Return an event descriptor
- return {
- name: event,
- callback: fn,
- un: function un(e, fn) {
- return _this.un(e, fn);
- }
- };
- }
- /**
- * Remove an event handler.
- *
- * @param {string} event Name of the event the listener that should be
- * removed listens to
- * @param {function} fn The callback that should be removed
- */
- }, {
- key: "un",
- value: function un(event, fn) {
- if (!this.handlers) {
- return;
- }
- var handlers = this.handlers[event];
- var i;
- if (handlers) {
- if (fn) {
- for (i = handlers.length - 1; i >= 0; i--) {
- if (handlers[i] == fn) {
- handlers.splice(i, 1);
- }
- }
- } else {
- handlers.length = 0;
- }
- }
- }
- /**
- * Remove all event handlers.
- */
- }, {
- key: "unAll",
- value: function unAll() {
- this.handlers = null;
- }
- /**
- * Attach a handler to an event. The handler is executed at most once per
- * event type.
- *
- * @param {string} event The event to listen to
- * @param {function} handler The callback that is only to be called once
- * @return {ListenerDescriptor} The event descriptor
- */
- }, {
- key: "once",
- value: function once(event, handler) {
- var _this2 = this;
- var fn = function fn() {
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
- args[_key] = arguments[_key];
- }
- /* eslint-disable no-invalid-this */
- handler.apply(_this2, args);
- /* eslint-enable no-invalid-this */
- setTimeout(function () {
- _this2.un(event, fn);
- }, 0);
- };
- return this.on(event, fn);
- }
- /**
- * Disable firing a list of events by name. When specified, event handlers for any event type
- * passed in here will not be called.
- *
- * @since 4.0.0
- * @param {string[]} eventNames an array of event names to disable emissions for
- * @example
- * // disable seek and interaction events
- * wavesurfer.setDisabledEventEmissions(['seek', 'interaction']);
- */
- }, {
- key: "setDisabledEventEmissions",
- value: function setDisabledEventEmissions(eventNames) {
- this._disabledEventEmissions = eventNames;
- }
- /**
- * plugins borrow part of this class without calling the constructor,
- * so we have to be careful about _disabledEventEmissions
- */
- }, {
- key: "_isDisabledEventEmission",
- value: function _isDisabledEventEmission(event) {
- return this._disabledEventEmissions && this._disabledEventEmissions.includes(event);
- }
- /**
- * Manually fire an event
- *
- * @param {string} event The event to fire manually
- * @param {...any} args The arguments with which to call the listeners
- */
- }, {
- key: "fireEvent",
- value: function fireEvent(event) {
- for (var _len2 = arguments.length, args = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
- args[_key2 - 1] = arguments[_key2];
- }
- if (!this.handlers || this._isDisabledEventEmission(event)) {
- return;
- }
- var handlers = this.handlers[event];
- handlers && handlers.forEach(function (fn) {
- fn.apply(void 0, args);
- });
- }
- }]);
- return Observer;
- }();
- exports.default = Observer;
- module.exports = exports.default;
- /***/ }),
- /***/ "./src/util/prevent-click.js":
- /*!***********************************!*\
- !*** ./src/util/prevent-click.js ***!
- \***********************************/
- /*! no static exports found */
- /***/ (function(module, exports, __webpack_require__) {
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = preventClick;
- /**
- * Stops propagation of click event and removes event listener
- *
- * @private
- * @param {object} event The click event
- */
- function preventClickHandler(event) {
- event.stopPropagation();
- document.body.removeEventListener('click', preventClickHandler, true);
- }
- /**
- * Starts listening for click event and prevent propagation
- *
- * @param {object} values Values
- */
- function preventClick(values) {
- document.body.addEventListener('click', preventClickHandler, true);
- }
- module.exports = exports.default;
- /***/ }),
- /***/ "./src/util/request-animation-frame.js":
- /*!*********************************************!*\
- !*** ./src/util/request-animation-frame.js ***!
- \*********************************************/
- /*! no static exports found */
- /***/ (function(module, exports, __webpack_require__) {
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
- /* eslint-disable valid-jsdoc */
- /**
- * Returns the `requestAnimationFrame` function for the browser, or a shim with
- * `setTimeout` if the function is not found
- *
- * @return {function} Available `requestAnimationFrame` function for the browser
- */
- var _default = (window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback, element) {
- return setTimeout(callback, 1000 / 60);
- }).bind(window);
- exports.default = _default;
- module.exports = exports.default;
- /***/ }),
- /***/ "./src/util/style.js":
- /*!***************************!*\
- !*** ./src/util/style.js ***!
- \***************************/
- /*! no static exports found */
- /***/ (function(module, exports, __webpack_require__) {
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = style;
- /**
- * Apply a map of styles to an element
- *
- * @param {HTMLElement} el The element that the styles will be applied to
- * @param {Object} styles The map of propName: attribute, both are used as-is
- *
- * @return {HTMLElement} el
- */
- function style(el, styles) {
- Object.keys(styles).forEach(function (prop) {
- if (el.style[prop] !== styles[prop]) {
- el.style[prop] = styles[prop];
- }
- });
- return el;
- }
- module.exports = exports.default;
- /***/ }),
- /***/ "./src/wavesurfer.js":
- /*!***************************!*\
- !*** ./src/wavesurfer.js ***!
- \***************************/
- /*! no static exports found */
- /***/ (function(module, exports, __webpack_require__) {
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
- var util = _interopRequireWildcard(__webpack_require__(/*! ./util */ "./src/util/index.js"));
- var _drawer = _interopRequireDefault(__webpack_require__(/*! ./drawer.multicanvas */ "./src/drawer.multicanvas.js"));
- var _webaudio = _interopRequireDefault(__webpack_require__(/*! ./webaudio */ "./src/webaudio.js"));
- var _mediaelement = _interopRequireDefault(__webpack_require__(/*! ./mediaelement */ "./src/mediaelement.js"));
- var _peakcache = _interopRequireDefault(__webpack_require__(/*! ./peakcache */ "./src/peakcache.js"));
- var _mediaelementWebaudio = _interopRequireDefault(__webpack_require__(/*! ./mediaelement-webaudio */ "./src/mediaelement-webaudio.js"));
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
- function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; }
- 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; }
- 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); }
- 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); }
- function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
- 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); }; }
- function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
- function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
- 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; } }
- function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
- 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); } }
- function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
- /*
- * This work is licensed under a BSD-3-Clause License.
- */
- /** @external {HTMLElement} https://developer.mozilla.org/en/docs/Web/API/HTMLElement */
- /** @external {OfflineAudioContext} https://developer.mozilla.org/en-US/docs/Web/API/OfflineAudioContext */
- /** @external {File} https://developer.mozilla.org/en-US/docs/Web/API/File */
- /** @external {Blob} https://developer.mozilla.org/en-US/docs/Web/API/Blob */
- /** @external {CanvasRenderingContext2D} https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D */
- /** @external {MediaStreamConstraints} https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamConstraints */
- /** @external {AudioNode} https://developer.mozilla.org/de/docs/Web/API/AudioNode */
- /**
- * @typedef {Object} WavesurferParams
- * @property {AudioContext} audioContext=null Use your own previously
- * initialized AudioContext or leave blank.
- * @property {number} audioRate=1 Speed at which to play audio. Lower number is
- * slower.
- * @property {ScriptProcessorNode} audioScriptProcessor=null Use your own previously
- * initialized ScriptProcessorNode or leave blank.
- * @property {boolean} autoCenter=true If a scrollbar is present, center the
- * waveform on current progress
- * @property {number} autoCenterRate=5 If autoCenter is active, rate at which the
- * waveform is centered
- * @property {boolean} autoCenterImmediately=false If autoCenter is active, immediately
- * center waveform on current progress
- * @property {string} backend='WebAudio' `'WebAudio'|'MediaElement'|'MediaElementWebAudio'` In most cases
- * you don't have to set this manually. MediaElement is a fallback for unsupported browsers.
- * MediaElementWebAudio allows to use WebAudio API also with big audio files, loading audio like with
- * MediaElement backend (HTML5 audio tag). You have to use the same methods of MediaElement backend for loading and
- * playback, giving also peaks, so the audio data are not decoded. In this way you can use WebAudio features, like filters,
- * also with audio with big duration. For example:
- * ` wavesurfer.load(url | HTMLMediaElement, peaks, preload, duration);
- * wavesurfer.play();
- * wavesurfer.setFilter(customFilter);
- * `
- * @property {string} backgroundColor=null Change background color of the
- * waveform container.
- * @property {number} barHeight=1 The height of the wave bars.
- * @property {number} barRadius=0 The radius of the wave bars. Makes bars rounded
- * @property {number} barGap=null The optional spacing between bars of the wave,
- * if not provided will be calculated in legacy format.
- * @property {number} barWidth=null Draw the waveform using bars.
- * @property {number} barMinHeight=null If specified, draw at least a bar of this height,
- * eliminating waveform gaps
- * @property {boolean} closeAudioContext=false Close and nullify all audio
- * contexts when the destroy method is called.
- * @property {!string|HTMLElement} container CSS selector or HTML element where
- * the waveform should be drawn. This is the only required parameter.
- * @property {string} cursorColor='#333' The fill color of the cursor indicating
- * the playhead position.
- * @property {number} cursorWidth=1 Measured in pixels.
- * @property {object} drawingContextAttributes={desynchronized: false} Drawing context
- * attributes.
- * @property {number} duration=null Optional audio length so pre-rendered peaks
- * can be display immediately for example.
- * @property {boolean} fillParent=true Whether to fill the entire container or
- * draw only according to `minPxPerSec`.
- * @property {boolean} forceDecode=false Force decoding of audio using web audio
- * when zooming to get a more detailed waveform.
- * @property {number} height=128 The height of the waveform. Measured in
- * pixels.
- * @property {boolean} hideScrollbar=false Whether to hide the horizontal
- * scrollbar when one would normally be shown.
- * @property {boolean} interact=true Whether the mouse interaction will be
- * enabled at initialization. You can switch this parameter at any time later
- * on.
- * @property {boolean} loopSelection=true (Use with regions plugin) Enable
- * looping of selected regions
- * @property {number} maxCanvasWidth=4000 Maximum width of a single canvas in
- * pixels, excluding a small overlap (2 * `pixelRatio`, rounded up to the next
- * even integer). If the waveform is longer than this value, additional canvases
- * will be used to render the waveform, which is useful for very large waveforms
- * that may be too wide for browsers to draw on a single canvas.
- * @property {boolean} mediaControls=false (Use with backend `MediaElement` or `MediaElementWebAudio`)
- * this enables the native controls for the media element
- * @property {string} mediaType='audio' (Use with backend `MediaElement` or `MediaElementWebAudio`)
- * `'audio'|'video'` ('video' only for `MediaElement`)
- * @property {number} minPxPerSec=20 Minimum number of pixels per second of
- * audio.
- * @property {boolean} normalize=false If true, normalize by the maximum peak
- * instead of 1.0.
- * @property {boolean} partialRender=false Use the PeakCache to improve
- * rendering speed of large waveforms
- * @property {number} pixelRatio=window.devicePixelRatio The pixel ratio used to
- * calculate display
- * @property {PluginDefinition[]} plugins=[] An array of plugin definitions to
- * register during instantiation, they will be directly initialised unless they
- * are added with the `deferInit` property set to true.
- * @property {string} progressColor='#555' The fill color of the part of the
- * waveform behind the cursor. When `progressColor` and `waveColor` are the same
- * the progress wave is not rendered at all.
- * @property {boolean} removeMediaElementOnDestroy=true Set to false to keep the
- * media element in the DOM when the player is destroyed. This is useful when
- * reusing an existing media element via the `loadMediaElement` method.
- * @property {Object} renderer=MultiCanvas Can be used to inject a custom
- * renderer.
- * @property {boolean|number} responsive=false If set to `true` resize the
- * waveform, when the window is resized. This is debounced with a `100ms`
- * timeout by default. If this parameter is a number it represents that timeout.
- * @property {boolean} rtl=false If set to `true`, renders waveform from
- * right-to-left.
- * @property {boolean} scrollParent=false Whether to scroll the container with a
- * lengthy waveform. Otherwise the waveform is shrunk to the container width
- * (see fillParent).
- * @property {number} skipLength=2 Number of seconds to skip with the
- * skipForward() and skipBackward() methods.
- * @property {boolean} splitChannels=false Render with separate waveforms for
- * the channels of the audio
- * @property {string} waveColor='#999' The fill color of the waveform after the
- * cursor.
- * @property {object} xhr={} XHR options. For example:
- * `let xhr = {
- * cache: 'default',
- * mode: 'cors',
- * method: 'GET',
- * credentials: 'same-origin',
- * redirect: 'follow',
- * referrer: 'client',
- * requestHeaders: [
- * {
- * key: 'Authorization',
- * value: 'my-token'
- * }
- * ]
- * };`
- */
- /**
- * @typedef {Object} PluginDefinition
- * @desc The Object used to describe a plugin
- * @example wavesurfer.addPlugin(pluginDefinition);
- * @property {string} name The name of the plugin, the plugin instance will be
- * added as a property to the wavesurfer instance under this name
- * @property {?Object} staticProps The properties that should be added to the
- * wavesurfer instance as static properties
- * @property {?boolean} deferInit Don't initialise plugin
- * automatically
- * @property {Object} params={} The plugin parameters, they are the first parameter
- * passed to the plugin class constructor function
- * @property {PluginClass} instance The plugin instance factory, is called with
- * the dependency specified in extends. Returns the plugin class.
- */
- /**
- * @interface PluginClass
- *
- * @desc This is the interface which is implemented by all plugin classes. Note
- * that this only turns into an observer after being passed through
- * `wavesurfer.addPlugin`.
- *
- * @extends {Observer}
- */
- var PluginClass = /*#__PURE__*/function () {
- _createClass(PluginClass, [{
- key: "create",
- /**
- * Plugin definition factory
- *
- * This function must be used to create a plugin definition which can be
- * used by wavesurfer to correctly instantiate the plugin.
- *
- * It returns a `PluginDefinition` object representing the plugin.
- *
- * @param {Object} params={} The plugin params (specific to the plugin)
- */
- value: function create(params) {}
- /**
- * Construct the plugin
- *
- * @param {Object} params={} The plugin params (specific to the plugin)
- * @param {Object} ws The wavesurfer instance
- */
- }]);
- function PluginClass(params, ws) {
- _classCallCheck(this, PluginClass);
- }
- /**
- * Initialise the plugin
- *
- * Start doing something. This is called by
- * `wavesurfer.initPlugin(pluginName)`
- */
- _createClass(PluginClass, [{
- key: "init",
- value: function init() {}
- /**
- * Destroy the plugin instance
- *
- * Stop doing something. This is called by
- * `wavesurfer.destroyPlugin(pluginName)`
- */
- }, {
- key: "destroy",
- value: function destroy() {}
- }]);
- return PluginClass;
- }();
- /**
- * WaveSurfer core library class
- *
- * @extends {Observer}
- * @example
- * const params = {
- * container: '#waveform',
- * waveColor: 'violet',
- * progressColor: 'purple'
- * };
- *
- * // initialise like this
- * const wavesurfer = WaveSurfer.create(params);
- *
- * // or like this ...
- * const wavesurfer = new WaveSurfer(params);
- * wavesurfer.init();
- *
- * // load audio file
- * wavesurfer.load('example/media/demo.wav');
- */
- var WaveSurfer = /*#__PURE__*/function (_util$Observer) {
- _inherits(WaveSurfer, _util$Observer);
- var _super = _createSuper(WaveSurfer);
- _createClass(WaveSurfer, null, [{
- key: "create",
- /** @private */
- /** @private */
- /**
- * Instantiate this class, call its `init` function and returns it
- *
- * @param {WavesurferParams} params The wavesurfer parameters
- * @return {Object} WaveSurfer instance
- * @example const wavesurfer = WaveSurfer.create(params);
- */
- value: function create(params) {
- var wavesurfer = new WaveSurfer(params);
- return wavesurfer.init();
- }
- /**
- * The library version number is available as a static property of the
- * WaveSurfer class
- *
- * @type {String}
- * @example
- * console.log('Using wavesurfer.js ' + WaveSurfer.VERSION);
- */
- }]);
- /**
- * Initialise wavesurfer instance
- *
- * @param {WavesurferParams} params Instantiation options for wavesurfer
- * @example
- * const wavesurfer = new WaveSurfer(params);
- * @returns {this} Wavesurfer instance
- */
- function WaveSurfer(params) {
- var _this;
- _classCallCheck(this, WaveSurfer);
- _this = _super.call(this);
- /**
- * Extract relevant parameters (or defaults)
- * @private
- */
- _this.defaultParams = {
- audioContext: null,
- audioScriptProcessor: null,
- audioRate: 1,
- autoCenter: true,
- autoCenterRate: 5,
- autoCenterImmediately: false,
- backend: 'WebAudio',
- backgroundColor: null,
- barHeight: 1,
- barRadius: 0,
- barGap: null,
- barMinHeight: null,
- container: null,
- cursorColor: '#333',
- cursorWidth: 1,
- dragSelection: true,
- drawingContextAttributes: {
- // Boolean that hints the user agent to reduce the latency
- // by desynchronizing the canvas paint cycle from the event
- // loop
- desynchronized: false
- },
- duration: null,
- fillParent: true,
- forceDecode: false,
- height: 128,
- hideScrollbar: false,
- interact: true,
- loopSelection: true,
- maxCanvasWidth: 4000,
- mediaContainer: null,
- mediaControls: false,
- mediaType: 'audio',
- minPxPerSec: 20,
- normalize: false,
- partialRender: false,
- pixelRatio: window.devicePixelRatio || screen.deviceXDPI / screen.logicalXDPI,
- plugins: [],
- progressColor: '#555',
- removeMediaElementOnDestroy: true,
- renderer: _drawer.default,
- responsive: false,
- rtl: false,
- scrollParent: false,
- skipLength: 2,
- splitChannels: false,
- splitChannelsOptions: {
- overlay: false,
- channelColors: {},
- filterChannels: []
- },
- waveColor: '#999',
- xhr: {}
- };
- _this.backends = {
- MediaElement: _mediaelement.default,
- WebAudio: _webaudio.default,
- MediaElementWebAudio: _mediaelementWebaudio.default
- };
- _this.util = util;
- _this.params = Object.assign({}, _this.defaultParams, params);
- /** @private */
- _this.container = 'string' == typeof params.container ? document.querySelector(_this.params.container) : _this.params.container;
- if (!_this.container) {
- throw new Error('Container element not found');
- }
- if (_this.params.mediaContainer == null) {
- /** @private */
- _this.mediaContainer = _this.container;
- } else if (typeof _this.params.mediaContainer == 'string') {
- /** @private */
- _this.mediaContainer = document.querySelector(_this.params.mediaContainer);
- } else {
- /** @private */
- _this.mediaContainer = _this.params.mediaContainer;
- }
- if (!_this.mediaContainer) {
- throw new Error('Media Container element not found');
- }
- if (_this.params.maxCanvasWidth <= 1) {
- throw new Error('maxCanvasWidth must be greater than 1');
- } else if (_this.params.maxCanvasWidth % 2 == 1) {
- throw new Error('maxCanvasWidth must be an even number');
- }
- if (_this.params.rtl === true) {
- util.style(_this.container, {
- transform: 'rotateY(180deg)'
- });
- }
- if (_this.params.backgroundColor) {
- _this.setBackgroundColor(_this.params.backgroundColor);
- }
- /**
- * @private Used to save the current volume when muting so we can
- * restore once unmuted
- * @type {number}
- */
- _this.savedVolume = 0;
- /**
- * @private The current muted state
- * @type {boolean}
- */
- _this.isMuted = false;
- /**
- * @private Will hold a list of event descriptors that need to be
- * canceled on subsequent loads of audio
- * @type {Object[]}
- */
- _this.tmpEvents = [];
- /**
- * @private Holds any running audio downloads
- * @type {Observer}
- */
- _this.currentRequest = null;
- /** @private */
- _this.arraybuffer = null;
- /** @private */
- _this.drawer = null;
- /** @private */
- _this.backend = null;
- /** @private */
- _this.peakCache = null; // cache constructor objects
- if (typeof _this.params.renderer !== 'function') {
- throw new Error('Renderer parameter is invalid');
- }
- /**
- * @private The uninitialised Drawer class
- */
- _this.Drawer = _this.params.renderer;
- /**
- * @private The uninitialised Backend class
- */
- // Back compat
- if (_this.params.backend == 'AudioElement') {
- _this.params.backend = 'MediaElement';
- }
- if ((_this.params.backend == 'WebAudio' || _this.params.backend === 'MediaElementWebAudio') && !_webaudio.default.prototype.supportsWebAudio.call(null)) {
- _this.params.backend = 'MediaElement';
- }
- _this.Backend = _this.backends[_this.params.backend];
- /**
- * @private map of plugin names that are currently initialised
- */
- _this.initialisedPluginList = {};
- /** @private */
- _this.isDestroyed = false;
- /**
- * Get the current ready status.
- *
- * @example const isReady = wavesurfer.isReady;
- * @return {boolean}
- */
- _this.isReady = false; // responsive debounced event listener. If this.params.responsive is not
- // set, this is never called. Use 100ms or this.params.responsive as
- // timeout for the debounce function.
- var prevWidth = 0;
- _this._onResize = util.debounce(function () {
- if (prevWidth != _this.drawer.wrapper.clientWidth && !_this.params.scrollParent) {
- prevWidth = _this.drawer.wrapper.clientWidth;
- _this.drawer.fireEvent('redraw');
- }
- }, typeof _this.params.responsive === 'number' ? _this.params.responsive : 100);
- return _possibleConstructorReturn(_this, _assertThisInitialized(_this));
- }
- /**
- * Initialise the wave
- *
- * @example
- * var wavesurfer = new WaveSurfer(params);
- * wavesurfer.init();
- * @return {this} The wavesurfer instance
- */
- _createClass(WaveSurfer, [{
- key: "init",
- value: function init() {
- this.registerPlugins(this.params.plugins);
- this.createDrawer();
- this.createBackend();
- this.createPeakCache();
- return this;
- }
- /**
- * Add and initialise array of plugins (if `plugin.deferInit` is falsey),
- * this function is called in the init function of wavesurfer
- *
- * @param {PluginDefinition[]} plugins An array of plugin definitions
- * @emits {WaveSurfer#plugins-registered} Called with the array of plugin definitions
- * @return {this} The wavesurfer instance
- */
- }, {
- key: "registerPlugins",
- value: function registerPlugins(plugins) {
- var _this2 = this;
- // first instantiate all the plugins
- plugins.forEach(function (plugin) {
- return _this2.addPlugin(plugin);
- }); // now run the init functions
- plugins.forEach(function (plugin) {
- // call init function of the plugin if deferInit is falsey
- // in that case you would manually use initPlugins()
- if (!plugin.deferInit) {
- _this2.initPlugin(plugin.name);
- }
- });
- this.fireEvent('plugins-registered', plugins);
- return this;
- }
- /**
- * Get a map of plugin names that are currently initialised
- *
- * @example wavesurfer.getPlugins();
- * @return {Object} Object with plugin names
- */
- }, {
- key: "getActivePlugins",
- value: function getActivePlugins() {
- return this.initialisedPluginList;
- }
- /**
- * Add a plugin object to wavesurfer
- *
- * @param {PluginDefinition} plugin A plugin definition
- * @emits {WaveSurfer#plugin-added} Called with the name of the plugin that was added
- * @example wavesurfer.addPlugin(WaveSurfer.minimap());
- * @return {this} The wavesurfer instance
- */
- }, {
- key: "addPlugin",
- value: function addPlugin(plugin) {
- var _this3 = this;
- if (!plugin.name) {
- throw new Error('Plugin does not have a name!');
- }
- if (!plugin.instance) {
- throw new Error("Plugin ".concat(plugin.name, " does not have an instance property!"));
- } // staticProps properties are applied to wavesurfer instance
- if (plugin.staticProps) {
- Object.keys(plugin.staticProps).forEach(function (pluginStaticProp) {
- /**
- * Properties defined in a plugin definition's `staticProps` property are added as
- * staticProps properties of the WaveSurfer instance
- */
- _this3[pluginStaticProp] = plugin.staticProps[pluginStaticProp];
- });
- }
- var Instance = plugin.instance; // turn the plugin instance into an observer
- var observerPrototypeKeys = Object.getOwnPropertyNames(util.Observer.prototype);
- observerPrototypeKeys.forEach(function (key) {
- Instance.prototype[key] = util.Observer.prototype[key];
- });
- /**
- * Instantiated plugin classes are added as a property of the wavesurfer
- * instance
- * @type {Object}
- */
- this[plugin.name] = new Instance(plugin.params || {}, this);
- this.fireEvent('plugin-added', plugin.name);
- return this;
- }
- /**
- * Initialise a plugin
- *
- * @param {string} name A plugin name
- * @emits WaveSurfer#plugin-initialised
- * @example wavesurfer.initPlugin('minimap');
- * @return {this} The wavesurfer instance
- */
- }, {
- key: "initPlugin",
- value: function initPlugin(name) {
- if (!this[name]) {
- throw new Error("Plugin ".concat(name, " has not been added yet!"));
- }
- if (this.initialisedPluginList[name]) {
- // destroy any already initialised plugins
- this.destroyPlugin(name);
- }
- this[name].init();
- this.initialisedPluginList[name] = true;
- this.fireEvent('plugin-initialised', name);
- return this;
- }
- /**
- * Destroy a plugin
- *
- * @param {string} name A plugin name
- * @emits WaveSurfer#plugin-destroyed
- * @example wavesurfer.destroyPlugin('minimap');
- * @returns {this} The wavesurfer instance
- */
- }, {
- key: "destroyPlugin",
- value: function destroyPlugin(name) {
- if (!this[name]) {
- throw new Error("Plugin ".concat(name, " has not been added yet and cannot be destroyed!"));
- }
- if (!this.initialisedPluginList[name]) {
- throw new Error("Plugin ".concat(name, " is not active and cannot be destroyed!"));
- }
- if (typeof this[name].destroy !== 'function') {
- throw new Error("Plugin ".concat(name, " does not have a destroy function!"));
- }
- this[name].destroy();
- delete this.initialisedPluginList[name];
- this.fireEvent('plugin-destroyed', name);
- return this;
- }
- /**
- * Destroy all initialised plugins. Convenience function to use when
- * wavesurfer is removed
- *
- * @private
- */
- }, {
- key: "destroyAllPlugins",
- value: function destroyAllPlugins() {
- var _this4 = this;
- Object.keys(this.initialisedPluginList).forEach(function (name) {
- return _this4.destroyPlugin(name);
- });
- }
- /**
- * Create the drawer and draw the waveform
- *
- * @private
- * @emits WaveSurfer#drawer-created
- */
- }, {
- key: "createDrawer",
- value: function createDrawer() {
- var _this5 = this;
- this.drawer = new this.Drawer(this.container, this.params);
- this.drawer.init();
- this.fireEvent('drawer-created', this.drawer);
- if (this.params.responsive !== false) {
- window.addEventListener('resize', this._onResize, true);
- window.addEventListener('orientationchange', this._onResize, true);
- }
- this.drawer.on('redraw', function () {
- _this5.drawBuffer();
- _this5.drawer.progress(_this5.backend.getPlayedPercents());
- }); // Click-to-seek
- this.drawer.on('click', function (e, progress) {
- setTimeout(function () {
- return _this5.seekTo(progress);
- }, 0);
- }); // Relay the scroll event from the drawer
- this.drawer.on('scroll', function (e) {
- if (_this5.params.partialRender) {
- _this5.drawBuffer();
- }
- _this5.fireEvent('scroll', e);
- });
- }
- /**
- * Create the backend
- *
- * @private
- * @emits WaveSurfer#backend-created
- */
- }, {
- key: "createBackend",
- value: function createBackend() {
- var _this6 = this;
- if (this.backend) {
- this.backend.destroy();
- }
- this.backend = new this.Backend(this.params);
- this.backend.init();
- this.fireEvent('backend-created', this.backend);
- this.backend.on('finish', function () {
- _this6.drawer.progress(_this6.backend.getPlayedPercents());
- _this6.fireEvent('finish');
- });
- this.backend.on('play', function () {
- return _this6.fireEvent('play');
- });
- this.backend.on('pause', function () {
- return _this6.fireEvent('pause');
- });
- this.backend.on('audioprocess', function (time) {
- _this6.drawer.progress(_this6.backend.getPlayedPercents());
- _this6.fireEvent('audioprocess', time);
- }); // only needed for MediaElement and MediaElementWebAudio backend
- if (this.params.backend === 'MediaElement' || this.params.backend === 'MediaElementWebAudio') {
- this.backend.on('seek', function () {
- _this6.drawer.progress(_this6.backend.getPlayedPercents());
- });
- this.backend.on('volume', function () {
- var newVolume = _this6.getVolume();
- _this6.fireEvent('volume', newVolume);
- if (_this6.backend.isMuted !== _this6.isMuted) {
- _this6.isMuted = _this6.backend.isMuted;
- _this6.fireEvent('mute', _this6.isMuted);
- }
- });
- }
- }
- /**
- * Create the peak cache
- *
- * @private
- */
- }, {
- key: "createPeakCache",
- value: function createPeakCache() {
- if (this.params.partialRender) {
- this.peakCache = new _peakcache.default();
- }
- }
- /**
- * Get the duration of the audio clip
- *
- * @example const duration = wavesurfer.getDuration();
- * @return {number} Duration in seconds
- */
- }, {
- key: "getDuration",
- value: function getDuration() {
- return this.backend.getDuration();
- }
- /**
- * Get the current playback position
- *
- * @example const currentTime = wavesurfer.getCurrentTime();
- * @return {number} Playback position in seconds
- */
- }, {
- key: "getCurrentTime",
- value: function getCurrentTime() {
- return this.backend.getCurrentTime();
- }
- /**
- * Set the current play time in seconds.
- *
- * @param {number} seconds A positive number in seconds. E.g. 10 means 10
- * seconds, 60 means 1 minute
- */
- }, {
- key: "setCurrentTime",
- value: function setCurrentTime(seconds) {
- if (seconds >= this.getDuration()) {
- this.seekTo(1);
- } else {
- this.seekTo(seconds / this.getDuration());
- }
- }
- /**
- * Starts playback from the current position. Optional start and end
- * measured in seconds can be used to set the range of audio to play.
- *
- * @param {?number} start Position to start at
- * @param {?number} end Position to end at
- * @emits WaveSurfer#interaction
- * @return {Promise} Result of the backend play method
- * @example
- * // play from second 1 to 5
- * wavesurfer.play(1, 5);
- */
- }, {
- key: "play",
- value: function play(start, end) {
- var _this7 = this;
- this.fireEvent('interaction', function () {
- return _this7.play(start, end);
- });
- return this.backend.play(start, end);
- }
- /**
- * Set a point in seconds for playback to stop at.
- *
- * @param {number} position Position (in seconds) to stop at
- * @version 3.3.0
- */
- }, {
- key: "setPlayEnd",
- value: function setPlayEnd(position) {
- this.backend.setPlayEnd(position);
- }
- /**
- * Stops and pauses playback
- *
- * @example wavesurfer.pause();
- * @return {Promise} Result of the backend pause method
- */
- }, {
- key: "pause",
- value: function pause() {
- if (!this.backend.isPaused()) {
- return this.backend.pause();
- }
- }
- /**
- * Toggle playback
- *
- * @example wavesurfer.playPause();
- * @return {Promise} Result of the backend play or pause method
- */
- }, {
- key: "playPause",
- value: function playPause() {
- return this.backend.isPaused() ? this.play() : this.pause();
- }
- /**
- * Get the current playback state
- *
- * @example const isPlaying = wavesurfer.isPlaying();
- * @return {boolean} False if paused, true if playing
- */
- }, {
- key: "isPlaying",
- value: function isPlaying() {
- return !this.backend.isPaused();
- }
- /**
- * Skip backward
- *
- * @param {?number} seconds Amount to skip back, if not specified `skipLength`
- * is used
- * @example wavesurfer.skipBackward();
- */
- }, {
- key: "skipBackward",
- value: function skipBackward(seconds) {
- this.skip(-seconds || -this.params.skipLength);
- }
- /**
- * Skip forward
- *
- * @param {?number} seconds Amount to skip back, if not specified `skipLength`
- * is used
- * @example wavesurfer.skipForward();
- */
- }, {
- key: "skipForward",
- value: function skipForward(seconds) {
- this.skip(seconds || this.params.skipLength);
- }
- /**
- * Skip a number of seconds from the current position (use a negative value
- * to go backwards).
- *
- * @param {number} offset Amount to skip back or forwards
- * @example
- * // go back 2 seconds
- * wavesurfer.skip(-2);
- */
- }, {
- key: "skip",
- value: function skip(offset) {
- var duration = this.getDuration() || 1;
- var position = this.getCurrentTime() || 0;
- position = Math.max(0, Math.min(duration, position + (offset || 0)));
- this.seekAndCenter(position / duration);
- }
- /**
- * Seeks to a position and centers the view
- *
- * @param {number} progress Between 0 (=beginning) and 1 (=end)
- * @example
- * // seek and go to the middle of the audio
- * wavesurfer.seekTo(0.5);
- */
- }, {
- key: "seekAndCenter",
- value: function seekAndCenter(progress) {
- this.seekTo(progress);
- this.drawer.recenter(progress);
- }
- /**
- * Seeks to a position
- *
- * @param {number} progress Between 0 (=beginning) and 1 (=end)
- * @emits WaveSurfer#interaction
- * @emits WaveSurfer#seek
- * @example
- * // seek to the middle of the audio
- * wavesurfer.seekTo(0.5);
- */
- }, {
- key: "seekTo",
- value: function seekTo(progress) {
- var _this8 = this;
- // return an error if progress is not a number between 0 and 1
- if (typeof progress !== 'number' || !isFinite(progress) || progress < 0 || progress > 1) {
- throw new Error('Error calling wavesurfer.seekTo, parameter must be a number between 0 and 1!');
- }
- this.fireEvent('interaction', function () {
- return _this8.seekTo(progress);
- });
- var paused = this.backend.isPaused(); // avoid draw wrong position while playing backward seeking
- if (!paused) {
- this.backend.pause();
- } // avoid small scrolls while paused seeking
- var oldScrollParent = this.params.scrollParent;
- this.params.scrollParent = false;
- this.backend.seekTo(progress * this.getDuration());
- this.drawer.progress(progress);
- if (!paused) {
- this.backend.play();
- }
- this.params.scrollParent = oldScrollParent;
- this.fireEvent('seek', progress);
- }
- /**
- * Stops and goes to the beginning.
- *
- * @example wavesurfer.stop();
- */
- }, {
- key: "stop",
- value: function stop() {
- this.pause();
- this.seekTo(0);
- this.drawer.progress(0);
- }
- /**
- * Sets the ID of the audio device to use for output and returns a Promise.
- *
- * @param {string} deviceId String value representing underlying output
- * device
- * @returns {Promise} `Promise` that resolves to `undefined` when there are
- * no errors detected.
- */
- }, {
- key: "setSinkId",
- value: function setSinkId(deviceId) {
- return this.backend.setSinkId(deviceId);
- }
- /**
- * Set the playback volume.
- *
- * @param {number} newVolume A value between 0 and 1, 0 being no
- * volume and 1 being full volume.
- * @emits WaveSurfer#volume
- */
- }, {
- key: "setVolume",
- value: function setVolume(newVolume) {
- this.backend.setVolume(newVolume);
- this.fireEvent('volume', newVolume);
- }
- /**
- * Get the playback volume.
- *
- * @return {number} A value between 0 and 1, 0 being no
- * volume and 1 being full volume.
- */
- }, {
- key: "getVolume",
- value: function getVolume() {
- return this.backend.getVolume();
- }
- /**
- * Set the playback rate.
- *
- * @param {number} rate A positive number. E.g. 0.5 means half the normal
- * speed, 2 means double speed and so on.
- * @example wavesurfer.setPlaybackRate(2);
- */
- }, {
- key: "setPlaybackRate",
- value: function setPlaybackRate(rate) {
- this.backend.setPlaybackRate(rate);
- }
- /**
- * Get the playback rate.
- *
- * @return {number} The current playback rate.
- */
- }, {
- key: "getPlaybackRate",
- value: function getPlaybackRate() {
- return this.backend.getPlaybackRate();
- }
- /**
- * Toggle the volume on and off. If not currently muted it will save the
- * current volume value and turn the volume off. If currently muted then it
- * will restore the volume to the saved value, and then rest the saved
- * value.
- *
- * @example wavesurfer.toggleMute();
- */
- }, {
- key: "toggleMute",
- value: function toggleMute() {
- this.setMute(!this.isMuted);
- }
- /**
- * Enable or disable muted audio
- *
- * @param {boolean} mute Specify `true` to mute audio.
- * @emits WaveSurfer#volume
- * @emits WaveSurfer#mute
- * @example
- * // unmute
- * wavesurfer.setMute(false);
- * console.log(wavesurfer.getMute()) // logs false
- */
- }, {
- key: "setMute",
- value: function setMute(mute) {
- // ignore all muting requests if the audio is already in that state
- if (mute === this.isMuted) {
- this.fireEvent('mute', this.isMuted);
- return;
- }
- if (this.backend.setMute) {
- // Backends such as the MediaElement backend have their own handling
- // of mute, let them handle it.
- this.backend.setMute(mute);
- this.isMuted = mute;
- } else {
- if (mute) {
- // If currently not muted then save current volume,
- // turn off the volume and update the mute properties
- this.savedVolume = this.backend.getVolume();
- this.backend.setVolume(0);
- this.isMuted = true;
- this.fireEvent('volume', 0);
- } else {
- // If currently muted then restore to the saved volume
- // and update the mute properties
- this.backend.setVolume(this.savedVolume);
- this.isMuted = false;
- this.fireEvent('volume', this.savedVolume);
- }
- }
- this.fireEvent('mute', this.isMuted);
- }
- /**
- * Get the current mute status.
- *
- * @example const isMuted = wavesurfer.getMute();
- * @return {boolean} Current mute status
- */
- }, {
- key: "getMute",
- value: function getMute() {
- return this.isMuted;
- }
- /**
- * Get the list of current set filters as an array.
- *
- * Filters must be set with setFilters method first
- *
- * @return {array} List of enabled filters
- */
- }, {
- key: "getFilters",
- value: function getFilters() {
- return this.backend.filters || [];
- }
- /**
- * Toggles `scrollParent` and redraws
- *
- * @example wavesurfer.toggleScroll();
- */
- }, {
- key: "toggleScroll",
- value: function toggleScroll() {
- this.params.scrollParent = !this.params.scrollParent;
- this.drawBuffer();
- }
- /**
- * Toggle mouse interaction
- *
- * @example wavesurfer.toggleInteraction();
- */
- }, {
- key: "toggleInteraction",
- value: function toggleInteraction() {
- this.params.interact = !this.params.interact;
- }
- /**
- * Get the fill color of the waveform after the cursor.
- *
- * @return {string} A CSS color string.
- */
- }, {
- key: "getWaveColor",
- value: function getWaveColor() {
- return this.params.waveColor;
- }
- /**
- * Set the fill color of the waveform after the cursor.
- *
- * @param {string} color A CSS color string.
- * @example wavesurfer.setWaveColor('#ddd');
- */
- }, {
- key: "setWaveColor",
- value: function setWaveColor(color) {
- this.params.waveColor = color;
- this.drawBuffer();
- }
- /**
- * Get the fill color of the waveform behind the cursor.
- *
- * @return {string} A CSS color string.
- */
- }, {
- key: "getProgressColor",
- value: function getProgressColor() {
- return this.params.progressColor;
- }
- /**
- * Set the fill color of the waveform behind the cursor.
- *
- * @param {string} color A CSS color string.
- * @example wavesurfer.setProgressColor('#400');
- */
- }, {
- key: "setProgressColor",
- value: function setProgressColor(color) {
- this.params.progressColor = color;
- this.drawBuffer();
- }
- /**
- * Get the background color of the waveform container.
- *
- * @return {string} A CSS color string.
- */
- }, {
- key: "getBackgroundColor",
- value: function getBackgroundColor() {
- return this.params.backgroundColor;
- }
- /**
- * Set the background color of the waveform container.
- *
- * @param {string} color A CSS color string.
- * @example wavesurfer.setBackgroundColor('#FF00FF');
- */
- }, {
- key: "setBackgroundColor",
- value: function setBackgroundColor(color) {
- this.params.backgroundColor = color;
- util.style(this.container, {
- background: this.params.backgroundColor
- });
- }
- /**
- * Get the fill color of the cursor indicating the playhead
- * position.
- *
- * @return {string} A CSS color string.
- */
- }, {
- key: "getCursorColor",
- value: function getCursorColor() {
- return this.params.cursorColor;
- }
- /**
- * Set the fill color of the cursor indicating the playhead
- * position.
- *
- * @param {string} color A CSS color string.
- * @example wavesurfer.setCursorColor('#222');
- */
- }, {
- key: "setCursorColor",
- value: function setCursorColor(color) {
- this.params.cursorColor = color;
- this.drawer.updateCursor();
- }
- /**
- * Get the height of the waveform.
- *
- * @return {number} Height measured in pixels.
- */
- }, {
- key: "getHeight",
- value: function getHeight() {
- return this.params.height;
- }
- /**
- * Set the height of the waveform.
- *
- * @param {number} height Height measured in pixels.
- * @example wavesurfer.setHeight(200);
- */
- }, {
- key: "setHeight",
- value: function setHeight(height) {
- this.params.height = height;
- this.drawer.setHeight(height * this.params.pixelRatio);
- this.drawBuffer();
- }
- /**
- * Hide channels from being drawn on the waveform if splitting channels.
- *
- * For example, if we want to draw only the peaks for the right stereo channel:
- *
- * const wavesurfer = new WaveSurfer.create({...splitChannels: true});
- * wavesurfer.load('stereo_audio.mp3');
- *
- * wavesurfer.setFilteredChannel([0]); <-- hide left channel peaks.
- *
- * @param {array} channelIndices Channels to be filtered out from drawing.
- * @version 4.0.0
- */
- }, {
- key: "setFilteredChannels",
- value: function setFilteredChannels(channelIndices) {
- this.params.splitChannelsOptions.filterChannels = channelIndices;
- this.drawBuffer();
- }
- /**
- * Get the correct peaks for current wave view-port and render wave
- *
- * @private
- * @emits WaveSurfer#redraw
- */
- }, {
- key: "drawBuffer",
- value: function drawBuffer() {
- var nominalWidth = Math.round(this.getDuration() * this.params.minPxPerSec * this.params.pixelRatio);
- var parentWidth = this.drawer.getWidth();
- var width = nominalWidth; // always start at 0 after zooming for scrolling : issue redraw left part
- var start = 0;
- var end = Math.max(start + parentWidth, width); // Fill container
- if (this.params.fillParent && (!this.params.scrollParent || nominalWidth < parentWidth)) {
- width = parentWidth;
- start = 0;
- end = width;
- }
- var peaks;
- if (this.params.partialRender) {
- var newRanges = this.peakCache.addRangeToPeakCache(width, start, end);
- var i;
- for (i = 0; i < newRanges.length; i++) {
- peaks = this.backend.getPeaks(width, newRanges[i][0], newRanges[i][1]);
- this.drawer.drawPeaks(peaks, width, newRanges[i][0], newRanges[i][1]);
- }
- } else {
- peaks = this.backend.getPeaks(width, start, end);
- this.drawer.drawPeaks(peaks, width, start, end);
- }
- this.fireEvent('redraw', peaks, width);
- }
- /**
- * Horizontally zooms the waveform in and out. It also changes the parameter
- * `minPxPerSec` and enables the `scrollParent` option. Calling the function
- * with a falsey parameter will reset the zoom state.
- *
- * @param {?number} pxPerSec Number of horizontal pixels per second of
- * audio, if none is set the waveform returns to unzoomed state
- * @emits WaveSurfer#zoom
- * @example wavesurfer.zoom(20);
- */
- }, {
- key: "zoom",
- value: function zoom(pxPerSec) {
- if (!pxPerSec) {
- this.params.minPxPerSec = this.defaultParams.minPxPerSec;
- this.params.scrollParent = false;
- } else {
- this.params.minPxPerSec = pxPerSec;
- this.params.scrollParent = true;
- }
- this.drawBuffer();
- this.drawer.progress(this.backend.getPlayedPercents());
- this.drawer.recenter(this.getCurrentTime() / this.getDuration());
- this.fireEvent('zoom', pxPerSec);
- }
- /**
- * Decode buffer and load
- *
- * @private
- * @param {ArrayBuffer} arraybuffer Buffer to process
- */
- }, {
- key: "loadArrayBuffer",
- value: function loadArrayBuffer(arraybuffer) {
- var _this9 = this;
- this.decodeArrayBuffer(arraybuffer, function (data) {
- if (!_this9.isDestroyed) {
- _this9.loadDecodedBuffer(data);
- }
- });
- }
- /**
- * Directly load an externally decoded AudioBuffer
- *
- * @private
- * @param {AudioBuffer} buffer Buffer to process
- * @emits WaveSurfer#ready
- */
- }, {
- key: "loadDecodedBuffer",
- value: function loadDecodedBuffer(buffer) {
- this.backend.load(buffer);
- this.drawBuffer();
- this.isReady = true;
- this.fireEvent('ready');
- }
- /**
- * Loads audio data from a Blob or File object
- *
- * @param {Blob|File} blob Audio data
- * @example
- */
- }, {
- key: "loadBlob",
- value: function loadBlob(blob) {
- var _this10 = this;
- // Create file reader
- var reader = new FileReader();
- reader.addEventListener('progress', function (e) {
- return _this10.onProgress(e);
- });
- reader.addEventListener('load', function (e) {
- return _this10.loadArrayBuffer(e.target.result);
- });
- reader.addEventListener('error', function () {
- return _this10.fireEvent('error', 'Error reading file');
- });
- reader.readAsArrayBuffer(blob);
- this.empty();
- }
- /**
- * Loads audio and re-renders the waveform.
- *
- * @param {string|HTMLMediaElement} url The url of the audio file or the
- * audio element with the audio
- * @param {number[]|Number.<Array[]>} peaks Wavesurfer does not have to decode
- * the audio to render the waveform if this is specified
- * @param {?string} preload (Use with backend `MediaElement` and `MediaElementWebAudio`)
- * `'none'|'metadata'|'auto'` Preload attribute for the media element
- * @param {?number} duration The duration of the audio. This is used to
- * render the peaks data in the correct size for the audio duration (as
- * befits the current `minPxPerSec` and zoom value) without having to decode
- * the audio.
- * @returns {void}
- * @throws Will throw an error if the `url` argument is empty.
- * @example
- * // uses fetch or media element to load file (depending on backend)
- * wavesurfer.load('http://example.com/demo.wav');
- *
- * // setting preload attribute with media element backend and supplying
- * // peaks
- * wavesurfer.load(
- * 'http://example.com/demo.wav',
- * [0.0218, 0.0183, 0.0165, 0.0198, 0.2137, 0.2888],
- * true
- * );
- */
- }, {
- key: "load",
- value: function load(url, peaks, preload, duration) {
- if (!url) {
- throw new Error('url parameter cannot be empty');
- }
- this.empty();
- if (preload) {
- // check whether the preload attribute will be usable and if not log
- // a warning listing the reasons why not and nullify the variable
- var preloadIgnoreReasons = {
- "Preload is not 'auto', 'none' or 'metadata'": ['auto', 'metadata', 'none'].indexOf(preload) === -1,
- 'Peaks are not provided': !peaks,
- "Backend is not of type 'MediaElement' or 'MediaElementWebAudio'": ['MediaElement', 'MediaElementWebAudio'].indexOf(this.params.backend) === -1,
- 'Url is not of type string': typeof url !== 'string'
- };
- var activeReasons = Object.keys(preloadIgnoreReasons).filter(function (reason) {
- return preloadIgnoreReasons[reason];
- });
- if (activeReasons.length) {
- // eslint-disable-next-line no-console
- console.warn('Preload parameter of wavesurfer.load will be ignored because:\n\t- ' + activeReasons.join('\n\t- ')); // stop invalid values from being used
- preload = null;
- }
- }
- switch (this.params.backend) {
- case 'WebAudio':
- return this.loadBuffer(url, peaks, duration);
- case 'MediaElement':
- case 'MediaElementWebAudio':
- return this.loadMediaElement(url, peaks, preload, duration);
- }
- }
- /**
- * Loads audio using Web Audio buffer backend.
- *
- * @private
- * @param {string} url URL of audio file
- * @param {number[]|Number.<Array[]>} peaks Peaks data
- * @param {?number} duration Optional duration of audio file
- * @returns {void}
- */
- }, {
- key: "loadBuffer",
- value: function loadBuffer(url, peaks, duration) {
- var _this11 = this;
- var load = function load(action) {
- if (action) {
- _this11.tmpEvents.push(_this11.once('ready', action));
- }
- return _this11.getArrayBuffer(url, function (data) {
- return _this11.loadArrayBuffer(data);
- });
- };
- if (peaks) {
- this.backend.setPeaks(peaks, duration);
- this.drawBuffer();
- this.tmpEvents.push(this.once('interaction', load));
- } else {
- return load();
- }
- }
- /**
- * Either create a media element, or load an existing media element.
- *
- * @private
- * @param {string|HTMLMediaElement} urlOrElt Either a path to a media file, or an
- * existing HTML5 Audio/Video Element
- * @param {number[]|Number.<Array[]>} peaks Array of peaks. Required to bypass web audio
- * dependency
- * @param {?boolean} preload Set to true if the preload attribute of the
- * audio element should be enabled
- * @param {?number} duration Optional duration of audio file
- */
- }, {
- key: "loadMediaElement",
- value: function loadMediaElement(urlOrElt, peaks, preload, duration) {
- var _this12 = this;
- var url = urlOrElt;
- if (typeof urlOrElt === 'string') {
- this.backend.load(url, this.mediaContainer, peaks, preload);
- } else {
- var elt = urlOrElt;
- this.backend.loadElt(elt, peaks); // If peaks are not provided,
- // url = element.src so we can get peaks with web audio
- url = elt.src;
- }
- this.tmpEvents.push(this.backend.once('canplay', function () {
- // ignore when backend was already destroyed
- if (!_this12.backend.destroyed) {
- _this12.drawBuffer();
- _this12.isReady = true;
- _this12.fireEvent('ready');
- }
- }), this.backend.once('error', function (err) {
- return _this12.fireEvent('error', err);
- }));
- if (peaks) {
- this.backend.setPeaks(peaks, duration);
- this.drawBuffer();
- } // If no pre-decoded peaks are provided, or are provided with
- // forceDecode flag, attempt to download the audio file and decode it
- // with Web Audio.
- if ((!peaks || this.params.forceDecode) && this.backend.supportsWebAudio()) {
- this.getArrayBuffer(url, function (arraybuffer) {
- _this12.decodeArrayBuffer(arraybuffer, function (buffer) {
- _this12.backend.buffer = buffer;
- _this12.backend.setPeaks(null);
- _this12.drawBuffer();
- _this12.fireEvent('waveform-ready');
- });
- });
- }
- }
- /**
- * Decode an array buffer and pass data to a callback
- *
- * @private
- * @param {Object} arraybuffer The array buffer to decode
- * @param {function} callback The function to call on complete
- */
- }, {
- key: "decodeArrayBuffer",
- value: function decodeArrayBuffer(arraybuffer, callback) {
- var _this13 = this;
- this.arraybuffer = arraybuffer;
- this.backend.decodeArrayBuffer(arraybuffer, function (data) {
- // Only use the decoded data if we haven't been destroyed or
- // another decode started in the meantime
- if (!_this13.isDestroyed && _this13.arraybuffer == arraybuffer) {
- callback(data);
- _this13.arraybuffer = null;
- }
- }, function () {
- return _this13.fireEvent('error', 'Error decoding audiobuffer');
- });
- }
- /**
- * Load an array buffer using fetch and pass the result to a callback
- *
- * @param {string} url The URL of the file object
- * @param {function} callback The function to call on complete
- * @returns {util.fetchFile} fetch call
- * @private
- */
- }, {
- key: "getArrayBuffer",
- value: function getArrayBuffer(url, callback) {
- var _this14 = this;
- var options = Object.assign({
- url: url,
- responseType: 'arraybuffer'
- }, this.params.xhr);
- var request = util.fetchFile(options);
- this.currentRequest = request;
- this.tmpEvents.push(request.on('progress', function (e) {
- _this14.onProgress(e);
- }), request.on('success', function (data) {
- callback(data);
- _this14.currentRequest = null;
- }), request.on('error', function (e) {
- _this14.fireEvent('error', e);
- _this14.currentRequest = null;
- }));
- return request;
- }
- /**
- * Called while the audio file is loading
- *
- * @private
- * @param {Event} e Progress event
- * @emits WaveSurfer#loading
- */
- }, {
- key: "onProgress",
- value: function onProgress(e) {
- var percentComplete;
- if (e.lengthComputable) {
- percentComplete = e.loaded / e.total;
- } else {
- // Approximate progress with an asymptotic
- // function, and assume downloads in the 1-3 MB range.
- percentComplete = e.loaded / (e.loaded + 1000000);
- }
- this.fireEvent('loading', Math.round(percentComplete * 100), e.target);
- }
- /**
- * Exports PCM data into a JSON array and opens in a new window.
- *
- * @param {number} length=1024 The scale in which to export the peaks
- * @param {number} accuracy=10000
- * @param {?boolean} noWindow Set to true to disable opening a new
- * window with the JSON
- * @param {number} start Start index
- * @param {number} end End index
- * @return {Promise} Promise that resolves with array of peaks
- */
- }, {
- key: "exportPCM",
- value: function exportPCM(length, accuracy, noWindow, start, end) {
- length = length || 1024;
- start = start || 0;
- accuracy = accuracy || 10000;
- noWindow = noWindow || false;
- var peaks = this.backend.getPeaks(length, start, end);
- var arr = [].map.call(peaks, function (val) {
- return Math.round(val * accuracy) / accuracy;
- });
- return new Promise(function (resolve, reject) {
- var json = JSON.stringify(arr);
- if (!noWindow) {
- window.open('data:application/json;charset=utf-8,' + encodeURIComponent(json));
- }
- resolve(json);
- });
- }
- /**
- * Save waveform image as data URI.
- *
- * The default format is `'image/png'`. Other supported types are
- * `'image/jpeg'` and `'image/webp'`.
- *
- * @param {string} format='image/png' A string indicating the image format.
- * The default format type is `'image/png'`.
- * @param {number} quality=1 A number between 0 and 1 indicating the image
- * quality to use for image formats that use lossy compression such as
- * `'image/jpeg'`` and `'image/webp'`.
- * @param {string} type Image data type to return. Either 'dataURL' (default)
- * or 'blob'.
- * @return {string|string[]|Promise} When using `'dataURL'` type this returns
- * a single data URL or an array of data URLs, one for each canvas. When using
- * `'blob'` type this returns a `Promise` resolving with an array of `Blob`
- * instances, one for each canvas.
- */
- }, {
- key: "exportImage",
- value: function exportImage(format, quality, type) {
- if (!format) {
- format = 'image/png';
- }
- if (!quality) {
- quality = 1;
- }
- if (!type) {
- type = 'dataURL';
- }
- return this.drawer.getImage(format, quality, type);
- }
- /**
- * Cancel any fetch request currently in progress
- */
- }, {
- key: "cancelAjax",
- value: function cancelAjax() {
- if (this.currentRequest && this.currentRequest.controller) {
- // If the current request has a ProgressHandler, then its ReadableStream might need to be cancelled too
- // See: Wavesurfer issue #2042
- // See Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1583815
- if (this.currentRequest._reader) {
- // Ignoring exceptions thrown by call to cancel()
- this.currentRequest._reader.cancel().catch(function (err) {});
- }
- this.currentRequest.controller.abort();
- this.currentRequest = null;
- }
- }
- /**
- * @private
- */
- }, {
- key: "clearTmpEvents",
- value: function clearTmpEvents() {
- this.tmpEvents.forEach(function (e) {
- return e.un();
- });
- }
- /**
- * Display empty waveform.
- */
- }, {
- key: "empty",
- value: function empty() {
- if (!this.backend.isPaused()) {
- this.stop();
- this.backend.disconnectSource();
- }
- this.isReady = false;
- this.cancelAjax();
- this.clearTmpEvents(); // empty drawer
- this.drawer.progress(0);
- this.drawer.setWidth(0);
- this.drawer.drawPeaks({
- length: this.drawer.getWidth()
- }, 0);
- }
- /**
- * Remove events, elements and disconnect WebAudio nodes.
- *
- * @emits WaveSurfer#destroy
- */
- }, {
- key: "destroy",
- value: function destroy() {
- this.destroyAllPlugins();
- this.fireEvent('destroy');
- this.cancelAjax();
- this.clearTmpEvents();
- this.unAll();
- if (this.params.responsive !== false) {
- window.removeEventListener('resize', this._onResize, true);
- window.removeEventListener('orientationchange', this._onResize, true);
- }
- if (this.backend) {
- this.backend.destroy();
- }
- if (this.drawer) {
- this.drawer.destroy();
- }
- this.isDestroyed = true;
- this.isReady = false;
- this.arraybuffer = null;
- }
- }]);
- return WaveSurfer;
- }(util.Observer);
- exports.default = WaveSurfer;
- WaveSurfer.VERSION = "4.1.1";
- WaveSurfer.util = util;
- module.exports = exports.default;
- /***/ }),
- /***/ "./src/webaudio.js":
- /*!*************************!*\
- !*** ./src/webaudio.js ***!
- \*************************/
- /*! no static exports found */
- /***/ (function(module, exports, __webpack_require__) {
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
- var util = _interopRequireWildcard(__webpack_require__(/*! ./util */ "./src/util/index.js"));
- function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; }
- 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; }
- 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); }
- 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; }
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
- 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); } }
- function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
- 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); }
- function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
- 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); }; }
- function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
- function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
- 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; } }
- function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
- // using constants to prevent someone writing the string wrong
- var PLAYING = 'playing';
- var PAUSED = 'paused';
- var FINISHED = 'finished';
- /**
- * WebAudio backend
- *
- * @extends {Observer}
- */
- var WebAudio = /*#__PURE__*/function (_util$Observer) {
- _inherits(WebAudio, _util$Observer);
- var _super = _createSuper(WebAudio);
- _createClass(WebAudio, [{
- key: "supportsWebAudio",
- /** scriptBufferSize: size of the processing buffer */
- /** audioContext: allows to process audio with WebAudio API */
- /** @private */
- /** @private */
- /**
- * Does the browser support this backend
- *
- * @return {boolean} Whether or not this browser supports this backend
- */
- value: function supportsWebAudio() {
- return !!(window.AudioContext || window.webkitAudioContext);
- }
- /**
- * Get the audio context used by this backend or create one
- *
- * @return {AudioContext} Existing audio context, or creates a new one
- */
- }, {
- key: "getAudioContext",
- value: function getAudioContext() {
- if (!window.WaveSurferAudioContext) {
- window.WaveSurferAudioContext = new (window.AudioContext || window.webkitAudioContext)();
- }
- return window.WaveSurferAudioContext;
- }
- /**
- * Get the offline audio context used by this backend or create one
- *
- * @param {number} sampleRate The sample rate to use
- * @return {OfflineAudioContext} Existing offline audio context, or creates
- * a new one
- */
- }, {
- key: "getOfflineAudioContext",
- value: function getOfflineAudioContext(sampleRate) {
- if (!window.WaveSurferOfflineAudioContext) {
- window.WaveSurferOfflineAudioContext = new (window.OfflineAudioContext || window.webkitOfflineAudioContext)(1, 2, sampleRate);
- }
- return window.WaveSurferOfflineAudioContext;
- }
- /**
- * Construct the backend
- *
- * @param {WavesurferParams} params Wavesurfer parameters
- */
- }]);
- function WebAudio(params) {
- var _this$stateBehaviors, _this$states;
- var _this;
- _classCallCheck(this, WebAudio);
- _this = _super.call(this);
- /** @private */
- _this.audioContext = null;
- _this.offlineAudioContext = null;
- _this.stateBehaviors = (_this$stateBehaviors = {}, _defineProperty(_this$stateBehaviors, PLAYING, {
- init: function init() {
- this.addOnAudioProcess();
- },
- getPlayedPercents: function getPlayedPercents() {
- var duration = this.getDuration();
- return this.getCurrentTime() / duration || 0;
- },
- getCurrentTime: function getCurrentTime() {
- return this.startPosition + this.getPlayedTime();
- }
- }), _defineProperty(_this$stateBehaviors, PAUSED, {
- init: function init() {
- this.removeOnAudioProcess();
- },
- getPlayedPercents: function getPlayedPercents() {
- var duration = this.getDuration();
- return this.getCurrentTime() / duration || 0;
- },
- getCurrentTime: function getCurrentTime() {
- return this.startPosition;
- }
- }), _defineProperty(_this$stateBehaviors, FINISHED, {
- init: function init() {
- this.removeOnAudioProcess();
- this.fireEvent('finish');
- },
- getPlayedPercents: function getPlayedPercents() {
- return 1;
- },
- getCurrentTime: function getCurrentTime() {
- return this.getDuration();
- }
- }), _this$stateBehaviors);
- _this.params = params;
- /** ac: Audio Context instance */
- _this.ac = params.audioContext || (_this.supportsWebAudio() ? _this.getAudioContext() : {});
- /**@private */
- _this.lastPlay = _this.ac.currentTime;
- /** @private */
- _this.startPosition = 0;
- /** @private */
- _this.scheduledPause = null;
- /** @private */
- _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);
- /** @private */
- _this.buffer = null;
- /** @private */
- _this.filters = [];
- /** gainNode: allows to control audio volume */
- _this.gainNode = null;
- /** @private */
- _this.mergedPeaks = null;
- /** @private */
- _this.offlineAc = null;
- /** @private */
- _this.peaks = null;
- /** @private */
- _this.playbackRate = 1;
- /** analyser: provides audio analysis information */
- _this.analyser = null;
- /** scriptNode: allows processing audio */
- _this.scriptNode = null;
- /** @private */
- _this.source = null;
- /** @private */
- _this.splitPeaks = [];
- /** @private */
- _this.state = null;
- /** @private */
- _this.explicitDuration = params.duration;
- /**
- * Boolean indicating if the backend was destroyed.
- */
- _this.destroyed = false;
- return _this;
- }
- /**
- * Initialise the backend, called in `wavesurfer.createBackend()`
- */
- _createClass(WebAudio, [{
- key: "init",
- value: function init() {
- this.createVolumeNode();
- this.createScriptNode();
- this.createAnalyserNode();
- this.setState(PAUSED);
- this.setPlaybackRate(this.params.audioRate);
- this.setLength(0);
- }
- /** @private */
- }, {
- key: "disconnectFilters",
- value: function disconnectFilters() {
- if (this.filters) {
- this.filters.forEach(function (filter) {
- filter && filter.disconnect();
- });
- this.filters = null; // Reconnect direct path
- this.analyser.connect(this.gainNode);
- }
- }
- /**
- * @private
- *
- * @param {string} state The new state
- */
- }, {
- key: "setState",
- value: function setState(state) {
- if (this.state !== this.states[state]) {
- this.state = this.states[state];
- this.state.init.call(this);
- }
- }
- /**
- * Unpacked `setFilters()`
- *
- * @param {...AudioNode} filters One or more filters to set
- */
- }, {
- key: "setFilter",
- value: function setFilter() {
- for (var _len = arguments.length, filters = new Array(_len), _key = 0; _key < _len; _key++) {
- filters[_key] = arguments[_key];
- }
- this.setFilters(filters);
- }
- /**
- * Insert custom Web Audio nodes into the graph
- *
- * @param {AudioNode[]} filters Packed filters array
- * @example
- * const lowpass = wavesurfer.backend.ac.createBiquadFilter();
- * wavesurfer.backend.setFilter(lowpass);
- */
- }, {
- key: "setFilters",
- value: function setFilters(filters) {
- // Remove existing filters
- this.disconnectFilters(); // Insert filters if filter array not empty
- if (filters && filters.length) {
- this.filters = filters; // Disconnect direct path before inserting filters
- this.analyser.disconnect(); // Connect each filter in turn
- filters.reduce(function (prev, curr) {
- prev.connect(curr);
- return curr;
- }, this.analyser).connect(this.gainNode);
- }
- }
- /** Create ScriptProcessorNode to process audio */
- }, {
- key: "createScriptNode",
- value: function createScriptNode() {
- if (this.params.audioScriptProcessor) {
- this.scriptNode = this.params.audioScriptProcessor;
- } else {
- if (this.ac.createScriptProcessor) {
- this.scriptNode = this.ac.createScriptProcessor(WebAudio.scriptBufferSize);
- } else {
- this.scriptNode = this.ac.createJavaScriptNode(WebAudio.scriptBufferSize);
- }
- }
- this.scriptNode.connect(this.ac.destination);
- }
- /** @private */
- }, {
- key: "addOnAudioProcess",
- value: function addOnAudioProcess() {
- var _this2 = this;
- this.scriptNode.onaudioprocess = function () {
- var time = _this2.getCurrentTime();
- if (time >= _this2.getDuration()) {
- _this2.setState(FINISHED);
- _this2.fireEvent('pause');
- } else if (time >= _this2.scheduledPause) {
- _this2.pause();
- } else if (_this2.state === _this2.states[PLAYING]) {
- _this2.fireEvent('audioprocess', time);
- }
- };
- }
- /** @private */
- }, {
- key: "removeOnAudioProcess",
- value: function removeOnAudioProcess() {
- this.scriptNode.onaudioprocess = function () {};
- }
- /** Create analyser node to perform audio analysis */
- }, {
- key: "createAnalyserNode",
- value: function createAnalyserNode() {
- this.analyser = this.ac.createAnalyser();
- this.analyser.connect(this.gainNode);
- }
- /**
- * Create the gain node needed to control the playback volume.
- *
- */
- }, {
- key: "createVolumeNode",
- value: function createVolumeNode() {
- // Create gain node using the AudioContext
- if (this.ac.createGain) {
- this.gainNode = this.ac.createGain();
- } else {
- this.gainNode = this.ac.createGainNode();
- } // Add the gain node to the graph
- this.gainNode.connect(this.ac.destination);
- }
- /**
- * Set the sink id for the media player
- *
- * @param {string} deviceId String value representing audio device id.
- * @returns {Promise} A Promise that resolves to `undefined` when there
- * are no errors.
- */
- }, {
- key: "setSinkId",
- value: function setSinkId(deviceId) {
- if (deviceId) {
- /**
- * The webaudio API doesn't currently support setting the device
- * output. Here we create an HTMLAudioElement, connect the
- * webaudio stream to that element and setSinkId there.
- */
- var audio = new window.Audio();
- if (!audio.setSinkId) {
- return Promise.reject(new Error('setSinkId is not supported in your browser'));
- }
- audio.autoplay = true;
- var dest = this.ac.createMediaStreamDestination();
- this.gainNode.disconnect();
- this.gainNode.connect(dest);
- audio.srcObject = dest.stream;
- return audio.setSinkId(deviceId);
- } else {
- return Promise.reject(new Error('Invalid deviceId: ' + deviceId));
- }
- }
- /**
- * Set the audio volume
- *
- * @param {number} value A floating point value between 0 and 1.
- */
- }, {
- key: "setVolume",
- value: function setVolume(value) {
- this.gainNode.gain.setValueAtTime(value, this.ac.currentTime);
- }
- /**
- * Get the current volume
- *
- * @return {number} value A floating point value between 0 and 1.
- */
- }, {
- key: "getVolume",
- value: function getVolume() {
- return this.gainNode.gain.value;
- }
- /**
- * Decode an array buffer and pass data to a callback
- *
- * @private
- * @param {ArrayBuffer} arraybuffer The array buffer to decode
- * @param {function} callback The function to call on complete.
- * @param {function} errback The function to call on error.
- */
- }, {
- key: "decodeArrayBuffer",
- value: function decodeArrayBuffer(arraybuffer, callback, errback) {
- if (!this.offlineAc) {
- this.offlineAc = this.getOfflineAudioContext(this.ac && this.ac.sampleRate ? this.ac.sampleRate : 44100);
- }
- this.offlineAc.decodeAudioData(arraybuffer, function (data) {
- return callback(data);
- }, errback);
- }
- /**
- * Set pre-decoded peaks
- *
- * @param {number[]|Number.<Array[]>} peaks Peaks data
- * @param {?number} duration Explicit duration
- */
- }, {
- key: "setPeaks",
- value: function setPeaks(peaks, duration) {
- if (duration != null) {
- this.explicitDuration = duration;
- }
- this.peaks = peaks;
- }
- /**
- * Set the rendered length (different from the length of the audio)
- *
- * @param {number} length The rendered length
- */
- }, {
- key: "setLength",
- value: function setLength(length) {
- // No resize, we can preserve the cached peaks.
- if (this.mergedPeaks && length == 2 * this.mergedPeaks.length - 1 + 2) {
- return;
- }
- this.splitPeaks = [];
- this.mergedPeaks = []; // Set the last element of the sparse array so the peak arrays are
- // appropriately sized for other calculations.
- var channels = this.buffer ? this.buffer.numberOfChannels : 1;
- var c;
- for (c = 0; c < channels; c++) {
- this.splitPeaks[c] = [];
- this.splitPeaks[c][2 * (length - 1)] = 0;
- this.splitPeaks[c][2 * (length - 1) + 1] = 0;
- }
- this.mergedPeaks[2 * (length - 1)] = 0;
- this.mergedPeaks[2 * (length - 1) + 1] = 0;
- }
- /**
- * Compute the max and min value of the waveform when broken into <length> subranges.
- *
- * @param {number} length How many subranges to break the waveform into.
- * @param {number} first First sample in the required range.
- * @param {number} last Last sample in the required range.
- * @return {number[]|Number.<Array[]>} Array of 2*<length> peaks or array of arrays of
- * peaks consisting of (max, min) values for each subrange.
- */
- }, {
- key: "getPeaks",
- value: function getPeaks(length, first, last) {
- if (this.peaks) {
- return this.peaks;
- }
- if (!this.buffer) {
- return [];
- }
- first = first || 0;
- last = last || length - 1;
- this.setLength(length);
- if (!this.buffer) {
- return this.params.splitChannels ? this.splitPeaks : this.mergedPeaks;
- }
- /**
- * The following snippet fixes a buffering data issue on the Safari
- * browser which returned undefined It creates the missing buffer based
- * on 1 channel, 4096 samples and the sampleRate from the current
- * webaudio context 4096 samples seemed to be the best fit for rendering
- * will review this code once a stable version of Safari TP is out
- */
- if (!this.buffer.length) {
- var newBuffer = this.createBuffer(1, 4096, this.sampleRate);
- this.buffer = newBuffer.buffer;
- }
- var sampleSize = this.buffer.length / length;
- var sampleStep = ~~(sampleSize / 10) || 1;
- var channels = this.buffer.numberOfChannels;
- var c;
- for (c = 0; c < channels; c++) {
- var peaks = this.splitPeaks[c];
- var chan = this.buffer.getChannelData(c);
- var i = void 0;
- for (i = first; i <= last; i++) {
- var start = ~~(i * sampleSize);
- var end = ~~(start + sampleSize);
- /**
- * Initialize the max and min to the first sample of this
- * subrange, so that even if the samples are entirely
- * on one side of zero, we still return the true max and
- * min values in the subrange.
- */
- var min = chan[start];
- var max = min;
- var j = void 0;
- for (j = start; j < end; j += sampleStep) {
- var value = chan[j];
- if (value > max) {
- max = value;
- }
- if (value < min) {
- min = value;
- }
- }
- peaks[2 * i] = max;
- peaks[2 * i + 1] = min;
- if (c == 0 || max > this.mergedPeaks[2 * i]) {
- this.mergedPeaks[2 * i] = max;
- }
- if (c == 0 || min < this.mergedPeaks[2 * i + 1]) {
- this.mergedPeaks[2 * i + 1] = min;
- }
- }
- }
- return this.params.splitChannels ? this.splitPeaks : this.mergedPeaks;
- }
- /**
- * Get the position from 0 to 1
- *
- * @return {number} Position
- */
- }, {
- key: "getPlayedPercents",
- value: function getPlayedPercents() {
- return this.state.getPlayedPercents.call(this);
- }
- /** @private */
- }, {
- key: "disconnectSource",
- value: function disconnectSource() {
- if (this.source) {
- this.source.disconnect();
- }
- }
- /**
- * Destroy all references with WebAudio, disconnecting audio nodes and closing Audio Context
- */
- }, {
- key: "destroyWebAudio",
- value: function destroyWebAudio() {
- this.disconnectFilters();
- this.disconnectSource();
- this.gainNode.disconnect();
- this.scriptNode.disconnect();
- this.analyser.disconnect(); // close the audioContext if closeAudioContext option is set to true
- if (this.params.closeAudioContext) {
- // check if browser supports AudioContext.close()
- if (typeof this.ac.close === 'function' && this.ac.state != 'closed') {
- this.ac.close();
- } // clear the reference to the audiocontext
- this.ac = null; // clear the actual audiocontext, either passed as param or the
- // global singleton
- if (!this.params.audioContext) {
- window.WaveSurferAudioContext = null;
- } else {
- this.params.audioContext = null;
- } // clear the offlineAudioContext
- window.WaveSurferOfflineAudioContext = null;
- }
- }
- /**
- * This is called when wavesurfer is destroyed
- */
- }, {
- key: "destroy",
- value: function destroy() {
- if (!this.isPaused()) {
- this.pause();
- }
- this.unAll();
- this.buffer = null;
- this.destroyed = true;
- this.destroyWebAudio();
- }
- /**
- * Loaded a decoded audio buffer
- *
- * @param {Object} buffer Decoded audio buffer to load
- */
- }, {
- key: "load",
- value: function load(buffer) {
- this.startPosition = 0;
- this.lastPlay = this.ac.currentTime;
- this.buffer = buffer;
- this.createSource();
- }
- /** @private */
- }, {
- key: "createSource",
- value: function createSource() {
- this.disconnectSource();
- this.source = this.ac.createBufferSource(); // adjust for old browsers
- this.source.start = this.source.start || this.source.noteGrainOn;
- this.source.stop = this.source.stop || this.source.noteOff;
- this.source.playbackRate.setValueAtTime(this.playbackRate, this.ac.currentTime);
- this.source.buffer = this.buffer;
- this.source.connect(this.analyser);
- }
- /**
- * @private
- *
- * some browsers require an explicit call to #resume before they will play back audio
- */
- }, {
- key: "resumeAudioContext",
- value: function resumeAudioContext() {
- if (this.ac.state == 'suspended') {
- this.ac.resume && this.ac.resume();
- }
- }
- /**
- * Used by `wavesurfer.isPlaying()` and `wavesurfer.playPause()`
- *
- * @return {boolean} Whether or not this backend is currently paused
- */
- }, {
- key: "isPaused",
- value: function isPaused() {
- return this.state !== this.states[PLAYING];
- }
- /**
- * Used by `wavesurfer.getDuration()`
- *
- * @return {number} Duration of loaded buffer
- */
- }, {
- key: "getDuration",
- value: function getDuration() {
- if (this.explicitDuration) {
- return this.explicitDuration;
- }
- if (!this.buffer) {
- return 0;
- }
- return this.buffer.duration;
- }
- /**
- * Used by `wavesurfer.seekTo()`
- *
- * @param {number} start Position to start at in seconds
- * @param {number} end Position to end at in seconds
- * @return {{start: number, end: number}} Object containing start and end
- * positions
- */
- }, {
- key: "seekTo",
- value: function seekTo(start, end) {
- if (!this.buffer) {
- return;
- }
- this.scheduledPause = null;
- if (start == null) {
- start = this.getCurrentTime();
- if (start >= this.getDuration()) {
- start = 0;
- }
- }
- if (end == null) {
- end = this.getDuration();
- }
- this.startPosition = start;
- this.lastPlay = this.ac.currentTime;
- if (this.state === this.states[FINISHED]) {
- this.setState(PAUSED);
- }
- return {
- start: start,
- end: end
- };
- }
- /**
- * Get the playback position in seconds
- *
- * @return {number} The playback position in seconds
- */
- }, {
- key: "getPlayedTime",
- value: function getPlayedTime() {
- return (this.ac.currentTime - this.lastPlay) * this.playbackRate;
- }
- /**
- * Plays the loaded audio region.
- *
- * @param {number} start Start offset in seconds, relative to the beginning
- * of a clip.
- * @param {number} end When to stop relative to the beginning of a clip.
- */
- }, {
- key: "play",
- value: function play(start, end) {
- if (!this.buffer) {
- return;
- } // need to re-create source on each playback
- this.createSource();
- var adjustedTime = this.seekTo(start, end);
- start = adjustedTime.start;
- end = adjustedTime.end;
- this.scheduledPause = end;
- this.source.start(0, start);
- this.resumeAudioContext();
- this.setState(PLAYING);
- this.fireEvent('play');
- }
- /**
- * Pauses the loaded audio.
- */
- }, {
- key: "pause",
- value: function pause() {
- this.scheduledPause = null;
- this.startPosition += this.getPlayedTime();
- this.source && this.source.stop(0);
- this.setState(PAUSED);
- this.fireEvent('pause');
- }
- /**
- * Returns the current time in seconds relative to the audio-clip's
- * duration.
- *
- * @return {number} The current time in seconds
- */
- }, {
- key: "getCurrentTime",
- value: function getCurrentTime() {
- return this.state.getCurrentTime.call(this);
- }
- /**
- * Returns the current playback rate. (0=no playback, 1=normal playback)
- *
- * @return {number} The current playback rate
- */
- }, {
- key: "getPlaybackRate",
- value: function getPlaybackRate() {
- return this.playbackRate;
- }
- /**
- * Set the audio source playback rate.
- *
- * @param {number} value The playback rate to use
- */
- }, {
- key: "setPlaybackRate",
- value: function setPlaybackRate(value) {
- value = value || 1;
- if (this.isPaused()) {
- this.playbackRate = value;
- } else {
- this.pause();
- this.playbackRate = value;
- this.play();
- }
- }
- /**
- * Set a point in seconds for playback to stop at.
- *
- * @param {number} end Position to end at
- * @version 3.3.0
- */
- }, {
- key: "setPlayEnd",
- value: function setPlayEnd(end) {
- this.scheduledPause = end;
- }
- }]);
- return WebAudio;
- }(util.Observer);
- exports.default = WebAudio;
- WebAudio.scriptBufferSize = 256;
- module.exports = exports.default;
- /***/ })
- /******/ });
- });
- //# sourceMappingURL=wavesurfer.js.map
|