@clxrity/react-audio
Version:
An interactive audio package for React
66 lines (64 loc) • 38.6 kB
JavaScript
import{jsx as ka}from"react/jsx-runtime";var re=({src:e,type:a,...o})=>{let r=a??(e?`audio/${e.split(".").pop()}`:"audio/*");return ka("source",{src:e,type:r,...o})};import{jsx as Pa}from"react/jsx-runtime";var R=({children:e,...a})=>Pa("button",{...a,type:"button",className:`focus:outline-none focus:shadow-outline
disabled:opacity-50 disabled:cursor-not-allowed
rounded-md px-4 py-2 transition-all duration-200 active:scale-95
disabled:active:scale-100 disabled:transition-none
cursor-pointer
`,children:e});import{useEffect as Qa,useMemo as Ja,useRef as _a}from"react";function ve({analyser:e,canvas:a,canvasContext:o,dataArray:r,bufferLength:u,color:d}){if(!o)return;o.clearRect(0,0,a.width,a.height),e.getByteFrequencyData(r),o.fillStyle=d;let t=a.height,l=a.width,L=Math.ceil(l/u)*2.5,c=0;for(let f=0;f<u;f++){let C=r[f]/255*t;o.fillRect(c,t-C,L,C),c+=L+1}}import{forwardRef as Aa,createElement as va}from"react";var Je=e=>e.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase(),ya=e=>e.replace(/^([A-Z])|[\s-_]+(\w)/g,(a,o,r)=>r?r.toUpperCase():o.toLowerCase()),Be=e=>{let a=ya(e);return a.charAt(0).toUpperCase()+a.slice(1)},ke=(...e)=>e.filter((a,o,r)=>!!a&&a.trim()!==""&&r.indexOf(a)===o).join(" ").trim(),_e=e=>{for(let a in e)if(a.startsWith("aria-")||a==="role"||a==="title")return!0};import{forwardRef as ba,createElement as $e}from"react";var je={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};var Ye=ba(({color:e="currentColor",size:a=24,strokeWidth:o=2,absoluteStrokeWidth:r,className:u="",children:d,iconNode:t,...l},L)=>$e("svg",{ref:L,...je,width:a,height:a,stroke:e,strokeWidth:r?Number(o)*24/Number(a):o,className:ke("lucide",u),...!d&&!_e(l)&&{"aria-hidden":"true"},...l},[...t.map(([c,f])=>$e(c,f)),...Array.isArray(d)?d:[d]]));var h=(e,a)=>{let o=Aa(({className:r,...u},d)=>va(Ye,{ref:d,iconNode:a,className:ke(`lucide-${Je(Be(e))}`,`lucide-${e}`,r),...u}));return o.displayName=Be(e),o};var Ba=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["rect",{x:"9",y:"9",width:"6",height:"6",rx:"1",key:"1ssd4o"}]],W=h("circle-stop",Ba);var Ma=[["path",{d:"M12 15V3",key:"m9g1x1"}],["path",{d:"M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4",key:"ih7n3h"}],["path",{d:"m7 10 5 5 5-5",key:"brsn70"}]],ue=h("download",Ma);var Da=[["path",{d:"M12 6a2 2 0 0 1 3.414-1.414l6 6a2 2 0 0 1 0 2.828l-6 6A2 2 0 0 1 12 18z",key:"b19h5q"}],["path",{d:"M2 6a2 2 0 0 1 3.414-1.414l6 6a2 2 0 0 1 0 2.828l-6 6A2 2 0 0 1 2 18z",key:"h7h5ge"}]],le=h("fast-forward",Da);var Fa=[["path",{d:"M5 22h14",key:"ehvnwv"}],["path",{d:"M5 2h14",key:"pdyrp9"}],["path",{d:"M17 22v-4.172a2 2 0 0 0-.586-1.414L12 12l-4.414 4.414A2 2 0 0 0 7 17.828V22",key:"1d314k"}],["path",{d:"M7 2v4.172a2 2 0 0 0 .586 1.414L12 12l4.414-4.414A2 2 0 0 0 17 6.172V2",key:"1vvvr6"}]],de=h("hourglass",Fa);var Ra=[["path",{d:"M21 12a9 9 0 1 1-6.219-8.56",key:"13zald"}]],N=h("loader-circle",Ra);var Ta=[["path",{d:"M12 19v3",key:"npa21l"}],["path",{d:"M19 10v2a7 7 0 0 1-14 0v-2",key:"1vc78b"}],["rect",{x:"9",y:"2",width:"6",height:"13",rx:"3",key:"s6n7sd"}]],se=h("mic",Ta);var qa=[["rect",{x:"14",y:"3",width:"5",height:"18",rx:"1",key:"kaeet6"}],["rect",{x:"5",y:"3",width:"5",height:"18",rx:"1",key:"1wsw3u"}]],fe=h("pause",qa);var Ua=[["path",{d:"M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z",key:"10ikf1"}]],ie=h("play",Ua);var Ha=[["path",{d:"M5 12h14",key:"1ays0h"}],["path",{d:"M12 5v14",key:"s699le"}]],ne=h("plus",Ha);var Oa=[["path",{d:"M12 6a2 2 0 0 0-3.414-1.414l-6 6a2 2 0 0 0 0 2.828l6 6A2 2 0 0 0 12 18z",key:"2a1g8i"}],["path",{d:"M22 6a2 2 0 0 0-3.414-1.414l-6 6a2 2 0 0 0 0 2.828l6 6A2 2 0 0 0 22 18z",key:"rg3s36"}]],ce=h("rewind",Oa);var za=[["path",{d:"M17.971 4.285A2 2 0 0 1 21 6v12a2 2 0 0 1-3.029 1.715l-9.997-5.998a2 2 0 0 1-.003-3.432z",key:"15892j"}],["path",{d:"M3 20V4",key:"1ptbpl"}]],pe=h("skip-back",za);var Ea=[["path",{d:"M21 4v16",key:"7j8fe9"}],["path",{d:"M6.029 4.285A2 2 0 0 0 3 6v12a2 2 0 0 0 3.029 1.715l9.997-5.998a2 2 0 0 0 .003-3.432z",key:"zs4d6"}]],me=h("skip-forward",Ea);var Va=[["rect",{x:"3",y:"3",width:"18",height:"18",rx:"2",key:"h1oib"}],["rect",{x:"8",y:"8",width:"8",height:"8",rx:"1",key:"z9xiuo"}]],Le=h("square-square",Va);var Ga=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}]],xe=h("square",Ga);var Wa=[["path",{d:"M10 11v6",key:"nco0om"}],["path",{d:"M14 11v6",key:"outv1u"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",key:"miytrc"}],["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",key:"e791ji"}]],Ie=h("trash-2",Wa);var Na=[["path",{d:"M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z",key:"uqj9uw"}],["path",{d:"M16 9a5 5 0 0 1 0 6",key:"1q6k2b"}]],he=h("volume-1",Na);var Xa=[["path",{d:"M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z",key:"uqj9uw"}],["path",{d:"M16 9a5 5 0 0 1 0 6",key:"1q6k2b"}],["path",{d:"M19.364 18.364a9 9 0 0 0 0-12.728",key:"ijwkga"}]],Ce=h("volume-2",Xa);var Ka=[["path",{d:"M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z",key:"uqj9uw"}],["line",{x1:"22",x2:"16",y1:"9",y2:"15",key:"1ewh16"}],["line",{x1:"16",x2:"22",y1:"9",y2:"15",key:"5ykzw1"}]],Y=h("volume-x",Ka);var Za=[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]],ge=h("x",Za);var A={Play:ie,Pause:fe,Stop:W,FastForward:le,Rewind:ce,SkipNext:me,SkipPrevious:pe,Loading:de,VolumeOff:Y,VolumeMute:Y,VolumeDown:he,VolumeUp:Ce,Selected:xe,Unselected:Le,Loader:N,Mic:se,Download:ue,Plus:ne,Trash:Ie,X:ge},O={primary:"rgb(236, 106, 177)",secondary:"rgb(121, 91, 132)",white:"#dddddd",black:"#111111"};function Me(e){e instanceof HTMLCanvasElement&&(e.width=e.clientWidth*window.devicePixelRatio,e.height=e.clientHeight*window.devicePixelRatio)}function De(e,a,o,r,u){let d=r.current;if(!d||!e)return()=>{};let t=d.getContext("2d"),l=0,L=()=>{l=requestAnimationFrame(L),t&&ve({analyser:e,canvas:d,canvasContext:t,dataArray:o,bufferLength:a,color:u})};return L(),()=>{l&&cancelAnimationFrame(l)}}import{jsx as ja}from"react/jsx-runtime";function Fe({analyser:e,bufferLength:a,dataArray:o,size:r,color:u,...d}){let t=_a(null),l=Ja(()=>()=>Me(t.current),[]);return Qa(()=>{let L=De(e,a,o,t,u||"white");return r||(window.addEventListener("resize",l),l()),()=>{window.removeEventListener("resize",l),L?.()}},[e,a,o,r,u,l]),ja("canvas",{ref:t,width:r||400,height:r||400,style:{color:u,zIndex:0,...d.style},...d})}import{jsx as ar}from"react/jsx-runtime";import{Fragment as Ya,jsx as Pe,jsxs as $a}from"react/jsx-runtime";var Re=({value:e,max:a,buffered:o,color:r,...u})=>{let d=a>0?e/a*100:0,t=a>0?o/a*100:0;return Pe(Ya,{children:$a("div",{className:"relative w-40 h-2 bg-gray-300 rounded overflow-hidden",children:[Pe("div",{className:"absolute top-0 left-0 h-full bg-gray-400 transition-all duration-200 rounded w-full",style:{width:`${t}%`,transition:"width 0.2s ease-in-out"}}),Pe("div",{className:"absolute top-0 left-0 h-full rounded transition-all duration-200",style:{width:`${d}%`,transition:"width 0.2s ease-in-out",backgroundColor:r||"#3b82f6"}}),Pe("input",{type:"range",value:e,max:a,min:0,className:`
h-1 w-20 appearance-none rounded-full bg-inherit/50
range-slider:h-2 range-slider:rounded-full
${u.className}
`,style:{backgroundImage:`linear-gradient(to right, ${r??"#3b82f6"} ${d}%, transparent 0%)`,border:`1px solid ${r}`},onChange:l=>u.onChange?.(l),onInput:l=>u.onChange?.(l),...u})]})})};import{jsx as et}from"react/jsx-runtime";function ee({value:e,onVolumeInput:a,color:o,...r}){return et("input",{type:"range",min:0,max:1,step:.01,value:e,onChange:u=>a(parseFloat(u.target.value)),className:`
h-1 w-20 appearance-none rounded-full bg-inherit/50
range-slider:h-2 range-slider:rounded-full
${r.className}
`,style:{backgroundImage:`linear-gradient(to right, ${o??"#3b82f6"} ${e*100}%, transparent 0%)`,border:`1px solid ${o}`},...r})}import{useEffect as Te,useRef as at,useState as ae,useCallback as X,forwardRef as tt}from"react";import{jsx as U,jsxs as ye}from"react/jsx-runtime";var K=tt(function({src:a,autoplay:o=!1,loop:r=!1,showProgress:u=!0,showVolume:d=!0,onNext:t,onPrev:l,showNextPrevControls:L=!0,size:c=24,color:f=O.primary,...C},g){let p=at(null),n=g&&typeof g=="object"?g:p,[q,y]=ae(!1),[D,w]=ae(!1),[B,k]=ae(.25),[m,P]=ae(0),[F,M]=ae(0),[T,z]=ae(0);Te(()=>{let i=n.current;i&&(i.src=a,i.load(),i.volume=B,i.loop=r,i.autoplay=o,o?i.play().then(()=>w(!0)).catch(()=>w(!1)):w(!i.paused))},[a,o,r,B]);let s=X(i=>{i.preventDefault(),i.stopPropagation(),n.current&&n.current.play().then(()=>w(!0)).catch(()=>w(!1))},[n]),x=X(()=>{n.current&&(n.current.pause(),w(!1))},[]),I=X(i=>{k(i.currentTarget.volume)},[]),v=X(()=>{let i=n.current;i&&(i.volume!==0?(i.volume=0,k(0)):(i.volume=.25,k(.25)))},[]),S=X(i=>{let E=i.currentTarget;if(E.duration>0){for(let Q=0;Q<E.buffered.length;Q++)if(E.buffered.start(E.buffered.length-1-Q)<E.currentTime){P(E.buffered.end(E.buffered.length-1-Q));break}}},[]),G=X(i=>{z(i.currentTarget.currentTime),S(i)},[S]),j=X(i=>{M(i.currentTarget.duration)},[]),oe=X(i=>{M(i.currentTarget.duration),y(!0)},[]),wa=i=>{let E=i.target,$=parseFloat(E.value);z($),n.current&&(n.current.currentTime=$)};return Te(()=>{o&&q&&n.current&&w(!0)},[o,q]),Te(()=>{let i=n.current;if(!i)return;let E=()=>w(!0),$=()=>w(!1),Q=()=>z(i.currentTime),Ze=()=>{i.buffered.length>0&&P(i.buffered.end(i.buffered.length-1))},Qe=()=>M(i.duration);return i.addEventListener("play",E),i.addEventListener("pause",$),i.addEventListener("timeupdate",Q),i.addEventListener("progress",Ze),i.addEventListener("loadedmetadata",Qe),()=>{i.removeEventListener("play",E),i.removeEventListener("pause",$),i.removeEventListener("timeupdate",Q),i.removeEventListener("progress",Ze),i.removeEventListener("loadedmetadata",Qe)}},[a]),ye("div",{className:"flex flex-col items-center gap-5 relative",children:[U("div",{className:"flex items-center gap-2",children:U("audio",{...C,ref:n,onCanPlay:oe,onTimeUpdate:G,onDurationChange:j,onVolumeChange:I,onPause:x,autoPlay:o,loop:r,preload:"auto",src:a,children:U(re,{src:a})})}),ye("div",{className:"flex flex-col items-center gap-4 z-30",children:[!D&&!o?U(R,{onClick:s,role:"button",name:"play",title:"play",children:U(A.Play,{})}):U(R,{onClick:x,role:"button",name:"pause",title:"pause",children:U(A.Pause,{})}),d&&ye("div",{className:"flex items-center gap-2",children:[U(R,{onClick:v,role:"button",name:"volume",title:"volume",children:B===0?U(A.VolumeOff,{}):B<.5?U(A.VolumeDown,{}):U(A.VolumeUp,{})}),U(ee,{size:c,color:f,value:B,onVolumeInput:i=>{n.current&&(n.current.volume=i,k(i))}})]})]}),ye("div",{className:"flex items-center gap-2 justify-between relative",children:[L&&l&&U(R,{onClick:l,role:"button",name:"prev",title:"previous",children:U(A.SkipPrevious,{})}),u&&U(Re,{color:f,value:T,max:F,buffered:m,onChange:wa}),L&&t&&U(R,{onClick:t,role:"button",name:"next",title:"next",children:U(A.SkipNext,{})})]})]})});import{useEffect as aa,useRef as He,useCallback as Oe}from"react";import{useState as ea,useRef as te,useCallback as qe,useEffect as ot}from"react";function Ue(){let[e,a]=ea(!1),[o,r]=ea(null),u=te(null),d=te([]),t=te(null),l=te(null),L=te(null),c=te(null),f=qe(async()=>{let p=await navigator.mediaDevices.getUserMedia({audio:!0});u.current=new MediaRecorder(p),d.current=[],u.current.ondataavailable=n=>{n.data.size>0&&d.current.push(n.data)},u.current.onstop=()=>{let n=new Blob(d.current,{type:"audio/webm"});r(URL.createObjectURL(n))},u.current.start();try{if(typeof AudioContext<"u"){t.current=new AudioContext,l.current=t.current.createAnalyser(),L.current=t.current.createMediaStreamSource(p),L.current.connect(l.current),l.current.fftSize=2048;let n=l.current.fftSize;c.current=new Uint8Array(n)}}catch{}a(!0)},[]),C=qe(()=>{u.current?.stop();try{u.current?.stream?.getTracks?.().forEach(n=>n.stop())}catch{}t.current?.close(),a(!1)},[]),g=qe(()=>!l.current||!c.current?[]:(l.current.getByteTimeDomainData(c.current),[...c.current]),[]);return ot(()=>()=>{t.current&&t.current.close();try{u.current?.stream?.getTracks?.().forEach(n=>n.stop())}catch{}},[]),{recording:e,audioUrl:o,startRecording:f,stopRecording:C,getWaveformData:g}}import{jsx as Z,jsxs as ta}from"react/jsx-runtime";function oa({className:e,waveColor:a=O.primary,width:o=400,height:r=80,onRecordingComplete:u}){let{recording:d,audioUrl:t,startRecording:l,stopRecording:L,getWaveformData:c}=Ue(),f=He(null),C=He(null),g=He(null);aa(()=>{t&&fetch(t).then(y=>y.blob()).then(y=>{g.current=y,u?.(y)}).catch(()=>{})},[t,u]);let p=Oe(()=>{if(!d)return;let y=c(),D=C.current;if(D&&y&&y.length){let w=D.getContext("2d");if(w){w.clearRect(0,0,D.width,D.height),w.strokeStyle=a,w.lineWidth=2,w.beginPath();let B=y,k=D.width/B.length,m=0;for(let P=0;P<B.length;P++){let F=B[P];if(F===void 0)continue;let T=F/128*D.height/2;P===0?w.moveTo(m,T):w.lineTo(m,T),m+=k}w.stroke()}}f.current=requestAnimationFrame(p)},[c,d,a]);aa(()=>(d?f.current=requestAnimationFrame(p):f.current&&(cancelAnimationFrame(f.current),f.current=null),()=>{f.current&&cancelAnimationFrame(f.current)}),[d,p]);let n=Oe(()=>{d?L():l()},[d,l,L]),q=Oe(()=>{if(!t)return;let y=document.createElement("a");y.href=t,y.download="recording.webm",document.body.appendChild(y),y.click(),document.body.removeChild(y)},[t]);return ta("div",{className:e,style:{display:"flex",flexDirection:"column",alignItems:"center",gap:12},children:[ta("div",{style:{display:"flex",gap:8},children:[Z(R,{onClick:n,title:d?"Stop":"Record",className:"cursor-pointer",children:d?Z(A.Stop,{}):Z(A.Mic,{})}),t&&Z(R,{onClick:q,title:"Download",className:"cursor-pointer",children:Z(A.Download,{})})]}),Z("canvas",{ref:C,width:o,height:r,style:{background:"#111",borderRadius:4,width:o,height:r}}),t&&Z("div",{style:{width:o},children:Z(K,{src:t,showNextPrevControls:!1,autoplay:!1,loop:!1,color:a})})]})}import{useEffect as rt}from"react";import{useState as Se,useRef as we,useCallback as V,useEffect as ra}from"react";function ze(){let[e,a]=Se([]),[o,r]=Se(!1),[u,d]=Se(.8),[t,l]=Se(4),[L,c]=Se(0),f=we(null),C=we(new Map),g=we(new Map),p=we(null),n=we(0);ra(()=>(typeof AudioContext<"u"&&(f.current=new AudioContext),()=>{f.current?.close()}),[]),ra(()=>(e.some(s=>s.isPlaying)||o?(n.current=Date.now(),p.current=setInterval(()=>{let s=(Date.now()-n.current)/1e3;c(s%t)},16)):(p.current&&(clearInterval(p.current),p.current=null),c(0)),()=>{p.current&&clearInterval(p.current)}),[e,o,t]);let q=V(()=>{let s=`track-${Date.now()}-${Math.random().toString(36).substr(2,9)}`,x={id:s,audioUrl:null,isPlaying:!1,isRecording:!1,volume:.8,duration:t};return a(I=>[...I,x]),s},[t]),y=V(s=>{let x=C.current.get(s);x&&x.state==="recording"&&x.stop(),C.current.delete(s);let I=g.current.get(s);I&&(I.pause(),I.src&&URL.revokeObjectURL(I.src)),g.current.delete(s),a(v=>v.filter(S=>S.id!==s))},[]),D=V(async s=>{try{let x=await navigator.mediaDevices.getUserMedia({audio:!0}),I=new MediaRecorder(x),v=[];I.ondataavailable=S=>{S.data.size>0&&v.push(S.data)},I.onstop=()=>{let S=new Blob(v,{type:"audio/webm"}),G=URL.createObjectURL(S);a(j=>j.map(oe=>oe.id===s?{...oe,audioUrl:G,isRecording:!1}:oe)),x.getTracks().forEach(j=>j.stop())},I.start(),C.current.set(s,I),a(S=>S.map(G=>G.id===s?{...G,isRecording:!0}:G)),r(!0),setTimeout(()=>{I.state==="recording"&&(I.stop(),r(!1))},t*1e3)}catch(x){console.error("Failed to start recording:",x)}},[t]),w=V(s=>{let x=C.current.get(s);x&&x.state==="recording"&&x.stop(),r(!1)},[]),B=V(s=>{a(x=>x.map(I=>{if(I.id===s&&I.audioUrl){let v=!I.isPlaying,S=g.current.get(s);return!S&&I.audioUrl&&(S=new Audio(I.audioUrl),S.loop=!0,S.volume=I.volume*u,g.current.set(s,S)),S&&(v?(S.currentTime=L%t,S.play().catch(console.error)):S.pause()),{...I,isPlaying:v}}return I}))},[L,t,u]),k=V(s=>{let x=g.current.get(s);x&&(x.pause(),x.src&&URL.revokeObjectURL(x.src)),a(I=>I.map(v=>v.id===s?{...v,audioUrl:null,isPlaying:!1,isRecording:!1}:v))},[]),m=V((s,x)=>{a(I=>I.map(v=>{if(v.id===s){let S=g.current.get(s);return S&&(S.volume=x*u),{...v,volume:x}}return v}))},[u]),P=V(s=>{d(s),g.current.forEach((x,I)=>{let v=e.find(S=>S.id===I);v&&x&&(x.volume=v.volume*s)})},[e]),F=V(s=>{l(s),a(x=>x.map(I=>({...I,duration:s})))},[]),M=V(()=>{e.forEach(s=>{s.audioUrl&&!s.isPlaying&&B(s.id)})},[e,B]),T=V(()=>{e.forEach(s=>{s.isPlaying&&B(s.id)})},[e,B]),z=V(()=>{e.forEach(s=>k(s.id))},[e,k]);return{tracks:e,isRecording:o,masterVolume:u,loopDuration:t,currentTime:L,addTrack:q,removeTrack:y,startRecording:D,stopRecording:w,togglePlayback:B,clearTrack:k,setTrackVolume:m,setMasterVolume:P,setLoopDuration:F,startAllTracks:M,stopAllTracks:T,clearAllTracks:z}}import{jsx as b,jsxs as H}from"react/jsx-runtime";function ut({track:e,isRecording:a,currentTime:o,loopDuration:r,color:u,onStartRecording:d,onStopRecording:t,onTogglePlayback:l,onClear:L,onVolumeChange:c,onRemove:f}){let C=o/r*100,g=!a&&!e.isRecording,p=!!e.audioUrl;return H("div",{style:{display:"flex",flexDirection:"column",gap:8,padding:"12px",border:`1px solid ${e.isPlaying?u:"#333"}`,borderRadius:8,background:e.isRecording?"rgba(255, 0, 0, 0.1)":"rgba(0, 0, 0, 0.2)",width:"100%"},children:[H("div",{style:{display:"flex",alignItems:"center",justifyContent:"center",gap:8,flexWrap:"wrap"},children:[b(R,{onClick:e.isRecording?t:d,disabled:!g&&!e.isRecording,title:e.isRecording?"Stop Recording":"Record",style:{minWidth:40,height:40},children:e.isRecording?b(A.Stop,{}):b(A.Mic,{})}),b(R,{onClick:l,disabled:!p,title:e.isPlaying?"Pause":"Play",style:{minWidth:40,height:40},children:e.isPlaying?b(A.Pause,{}):b(A.Play,{})}),b(R,{onClick:L,disabled:!p,title:"Clear Track",style:{minWidth:40,height:40},children:b(A.Trash,{})}),b(R,{onClick:f,title:"Remove Track",style:{minWidth:40,height:40},children:b(A.X,{})})]}),H("div",{style:{height:8,background:"#333",borderRadius:4,overflow:"hidden",position:"relative",width:"100%"},children:[e.isPlaying&&b("div",{style:{position:"absolute",left:0,top:0,height:"100%",width:`${C}%`,background:u,transition:"width 0.1s linear"}}),p&&b("div",{style:{position:"absolute",left:0,top:0,height:"100%",width:"100%",background:"rgba(255, 255, 255, 0.2)"}})]}),b("div",{style:{display:"flex",justifyContent:"center",alignItems:"center",width:"100%"},children:b("div",{style:{width:120},children:b(ee,{size:16,color:u,value:e.volume,onVolumeInput:c})})})]})}function ua({className:e,maxTracks:a=8,defaultLoopDuration:o=4,color:r=O.primary}){let{tracks:u,isRecording:d,masterVolume:t,loopDuration:l,currentTime:L,addTrack:c,removeTrack:f,startRecording:C,stopRecording:g,togglePlayback:p,clearTrack:n,setTrackVolume:q,setMasterVolume:y,setLoopDuration:D,startAllTracks:w,stopAllTracks:B,clearAllTracks:k}=ze();rt(()=>{D(o)},[o,D]);let m=u.length<a,P=u.some(M=>M.audioUrl),F=u.some(M=>M.isPlaying);return H("div",{className:e,style:{display:"flex",flexDirection:"column",gap:16,padding:16,border:"1px solid #333",borderRadius:8,background:"rgba(0, 0, 0, 0.1)",maxWidth:"100%",overflow:"hidden"},children:[H("div",{style:{display:"flex",flexDirection:"column",gap:12,paddingBottom:16,borderBottom:"1px solid #333"},children:[H("div",{style:{display:"flex",alignItems:"center",gap:8},children:[b("span",{style:{fontWeight:"bold",minWidth:100},children:"Loop Duration:"}),b("input",{type:"range",min:"1",max:"16",step:"0.5",value:l,onChange:M=>{let T=parseFloat(M.target.value);D(T)},style:{width:120,height:20,WebkitAppearance:"none",appearance:"none",background:"#333",borderRadius:10,outline:"none"},title:"Loop Duration","aria-label":"Loop Duration in seconds",className:"cursor-pointer"}),H("span",{style:{minWidth:40},children:[l,"s"]})]}),H("div",{style:{display:"flex",alignItems:"center",gap:8},children:[b("span",{style:{fontWeight:"bold",minWidth:100},children:"Master Volume:"}),b("div",{style:{width:100},children:b(ee,{size:20,color:r,value:t,onVolumeInput:y,className:"cursor-pointer"})})]})]}),H("div",{style:{display:"flex",justifyContent:"center",gap:12,paddingBottom:16,borderBottom:"1px solid #333"},children:[H(R,{onClick:c,disabled:!m,title:"Add Track",className:"cursor-pointer",children:[b(A.Plus,{})," Add Track"]}),H(R,{onClick:F?B:w,disabled:!P,title:F?"Stop All":"Play All",className:"cursor-pointer",children:[F?b(A.Pause,{}):b(A.Play,{}),F?"Stop All":"Play All"]}),H(R,{onClick:k,disabled:!P,title:"Clear All Tracks",className:"cursor-pointer",children:[b(A.Trash,{})," Clear All"]})]}),b("div",{style:{display:"flex",flexDirection:"column",gap:12},children:u.length===0?b("div",{style:{textAlign:"center",padding:32,color:"#666",fontStyle:"italic"},children:'No tracks yet. Click "Add Track" to get started.'}):u.map((M,T)=>H("div",{style:{display:"flex",flexDirection:"column",alignItems:"center",gap:8,width:"100%"},children:[H("div",{style:{fontWeight:"bold",color:M.isPlaying?r:"#666",fontSize:"1.1em",textAlign:"center"},children:["Track ",T+1]}),b("div",{style:{width:"100%",maxWidth:400,display:"flex",justifyContent:"center"},children:b(ut,{track:M,isRecording:d,currentTime:L,loopDuration:l,color:r,onStartRecording:()=>C(M.id),onStopRecording:()=>g(M.id),onTogglePlayback:()=>p(M.id),onClear:()=>n(M.id),onVolumeChange:z=>q(M.id,z),onRemove:()=>f(M.id)})})]},M.id))}),(d||F)&&H("div",{style:{textAlign:"center",padding:8,background:"rgba(0, 0, 0, 0.2)",borderRadius:4,fontSize:"0.9em"},children:[d&&b("span",{style:{color:"red"},children:"\u25CF Recording..."}),F&&H("span",{style:{color:r},children:["Playing \u2022 ",L.toFixed(1),"s / ",l,"s"]})]})]})}import{useCallback as la,useMemo as lt,useState as dt}from"react";import{jsx as st}from"react/jsx-runtime";function da({srcs:e,autoplay:a=!1,color:o=O.primary,showNextPrevControls:r=!0,showProgress:u=!0,showVolume:d=!0,shuffle:t=!1,onNext:l,onPrev:L,...c}){let[f,C]=dt(0),g=lt(()=>e[f]??"",[e,f]),p=la(()=>e.length===0?0:t?Math.floor(Math.random()*e.length):(f+1)%e.length,[f,t,e]),n=la(()=>e.length===0?0:t?Math.floor(Math.random()*e.length):(f-1+e.length)%e.length,[f,t,e]);return st(K,{color:o,autoplay:a,src:g,onNext:()=>{C(p()),l&&l()},onPrev:()=>{C(n()),L&&L()},showNextPrevControls:r,showProgress:u,showVolume:d,onEnded:()=>C(p()),...c})}import{useEffect as Ve,useMemo as nt,useRef as sa,useState as fa}from"react";import{useEffect as ft,useState as it}from"react";function Ee(e,a,o,r){let[u,d]=it(null);return ft(()=>{if(!e||!a||a.state==="closed"){d(null);return}o.current||(o.current=a.createMediaElementSource(e));let t=a.createAnalyser();return t.fftSize=r,o.current.connect(t),t.connect(a.destination),d(t),()=>{t.disconnect();try{o.current?.disconnect()}catch(l){console.warn("Error disconnecting source node:",l)}d(null)}},[e,a,r,o]),u?{analyser:u,getFrequencyData:()=>{let t=u.frequencyBinCount,l=new Uint8Array(t);return u.getByteFrequencyData(l),l}}:null}import{jsx as Ge,jsxs as ct}from"react/jsx-runtime";function ia({src:e,size:a=420,color:o=O.primary,autoplay:r=!1,loop:u=!1,showProgress:d=!0,showVolume:t=!0,fftSize:l=2048,onLoad:L,...c}){let f=sa(null),[C,g]=fa(!1),[p,n]=fa(null),q=sa(null);Ve(()=>{let B=requestAnimationFrame(()=>g(!!f.current));return()=>cancelAnimationFrame(B)},[]),Ve(()=>{if(C&&(!p||p.state==="closed")){let B=new AudioContext;n(B)}},[C,p]);let y=Ee(C?f.current:null,p,q,l),D=y?.analyser.frequencyBinCount,w=nt(()=>D?new Uint8Array(D):null,[D]);return Ve(()=>()=>{p&&p.state!=="closed"&&p.close(),q.current?.disconnect()},[p]),Ge("div",{...c,style:{display:"flex",justifyContent:"center",alignItems:"center",width:"100%",maxWidth:"400px",position:"relative",borderRadius:"8px",backgroundColor:"transparent",gap:"8px",minHeight:"200px",...c.style},children:ct("div",{style:{position:"relative",width:"100%",height:"100px"},children:[y?.analyser&&w&&D&&Ge(Fe,{analyser:y.analyser,bufferLength:D,dataArray:w,size:a,color:o,width:a,height:a,style:{position:"absolute",inset:0,width:"100%",height:"100%",opacity:.8,pointerEvents:"none",zIndex:0}}),Ge(K,{src:e,autoplay:r,loop:u,showProgress:d,showVolume:t,color:o,onLoad:L,showNextPrevControls:!1,size:a,ref:f})]})})}import{useEffect as We,useRef as Ne,useState as Xe}from"react";import{jsx as J,jsxs as _}from"react/jsx-runtime";function na({type:e="sine",frequency:a=440,gain:o=.5,isPlaying:r=!1,onPlayChange:u,showControls:d=!0,onFrequencyChange:t,onGainChange:l,...L}){let c=Ne(null),f=Ne(null),C=Ne(null),[g,p]=Xe(a),[n,q]=Xe(o),[y,D]=Xe(!!r),w=typeof r=="boolean"?r:y,B=()=>(c.current||(c.current=new AudioContext),c.current),k=()=>{try{f.current?.stop()}catch{}f.current?.disconnect(),C.current?.disconnect(),f.current=null,C.current=null};return We(()=>{if(w){let m=B();if(f.current){let P=c.current;f.current.frequency.setValueAtTime(g,P.currentTime),C.current.gain.setValueAtTime(n,P.currentTime)}else{let P=m.createOscillator(),F=m.createGain();P.type=e,P.frequency.setValueAtTime(g,m.currentTime),F.gain.setValueAtTime(n,m.currentTime),P.connect(F),F.connect(m.destination),P.start(),f.current=P,C.current=F}}else k();return()=>{}},[w,e,g,n]),We(()=>{let m=()=>{c.current&&c.current.state==="suspended"&&c.current.resume()};return window.addEventListener("pointerdown",m,{once:!0}),()=>{window.removeEventListener("pointerdown",m)}},[]),We(()=>()=>{k(),c.current&&c.current.state!=="closed"&&c.current.close().catch(()=>{}),c.current=null},[]),_("div",{...L,className:`flex flex-col gap-2 items-center ${L.className}`,children:[d&&J("div",{className:"flex items-center gap-2",children:J(R,{title:w?"Pause":"Play","aria-label":w?"Pause oscillator":"Play oscillator",onClick:()=>{typeof r=="boolean"&&u?u(!r):D(m=>!m)},children:w?J(A.Pause,{}):J(A.Play,{})})}),_("div",{className:"flex flex-col gap-2",children:[_("label",{className:"flex items-center gap-2",children:[_("span",{children:["Frequency: ",_("span",{className:"font-mono",children:[g," Hz"]})]}),J("input",{className:"disabled:opacity-50 disabled:cursor-not-allowed",type:"range",min:20,max:2e3,value:g,onChange:m=>{let P=parseFloat(m.target.value);p(P),t?.(P),f.current&&f.current.frequency.setValueAtTime(P,c.current?.currentTime??0)}})]}),_("label",{className:"flex items-center gap-2",children:[_("span",{children:["Gain: ",J("span",{className:"font-mono",children:n})]}),J("input",{type:"range",className:"disabled:opacity-50 disabled:cursor-not-allowed",min:0,max:1,step:.01,value:n,onChange:m=>{let P=parseFloat(m.target.value);q(P),l?.(P),C.current&&C.current.gain.setValueAtTime(P,c.current?.currentTime??0)}})]})]})]})}import{useCallback as pt,useEffect as mt,useRef as be,useState as ca}from"react";import{jsx as Ae,jsxs as Lt}from"react/jsx-runtime";function Ke({audioRef:e,fftSize:a=1024,width:o="100%",height:r="25%",minDecibels:u=-100,maxDecibels:d=-25,colorMap:t=["#111","#ff0000","#ffff00","#ffffff"],onFrameUpdate:l,fillStyle:L,loop:c=!1,smoothingTimeConstant:f=.8,...C}){let g=be(null),p=be(null),n=be(null),[q,y]=ca(!1),[D,w]=ca(!1),B=pt(()=>{if(q){e.current.pause(),y(!1);return}if(e.current){if(!p.current){let k=new AudioContext,m=k.createAnalyser();p.current=k,n.current=m,m.fftSize=a,m.minDecibels=u,m.maxDecibels=d,m.smoothingTimeConstant=f,k.createMediaElementSource(e.current).connect(m),m.connect(k.destination)}if(p.current.state==="suspended"&&p.current.resume(),e.current.paused){let k=e.current.play();k!==void 0&&k.then(()=>{y(!0)}).catch(m=>{console.error("Error playing audio:",m)})}c&&(e.current.loop=!0)}},[]);return mt(()=>{if(!g.current||!e.current)return;let k=g.current,m=k.getContext("2d");if(!m)return;k.width=800,k.height=400;let P=(T,z,s)=>`#${T.slice(1).match(/.{2}/g).map((I,v)=>{let S=parseInt(I,16),G=parseInt(z.slice(1).match(/.{2}/g)[v],16);return Math.round(S+s*(G-S)).toString(16).padStart(2,"0")}).join("")}`,F=T=>{let s=T/255*(t.length-1),x=Math.floor(s),I=s-x,v=t[x],S=t[x+1]||v;return P(v,S,I)},M=()=>{if(!k||!m||!n.current)return;let T=n.current.frequencyBinCount,z=new Uint8Array(T);n.current.getByteFrequencyData(z),m.fillStyle=L||"rgba(0, 0, 0, 0.5)",m.fillRect(0,0,k.width,k.height);for(let s=0;s<T;s++){let x=z[s],I=x/255*k.height,v=k.height-I,S=k.width/T;m.fillStyle=F(x),m.fillRect(s*S,v,S,I)}requestAnimationFrame(M),l?.(z)};q&&M()},[t,L,q,l]),Ae("canvas",{...C,onClick:()=>{B(),w(!0)},ref:g,style:{width:o,height:r},className:`border border-zinc-800/65 dark:border-zinc-500/65 rounded-md backdrop:invert-50 cursor-pointer ${D?"":"bg-zinc-700/50 animate-pulse hover:border-2 transition-all hover:bg-zinc-700/75 hover:animate-none"}`})}function pa({src:e,fftSize:a,width:o,height:r,minDecibels:u,maxDecibels:d,colorMap:t,smoothingTimeConstant:l,onFrameUpdate:L,loop:c,fillStyle:f,...C}){let g=be(null);return Lt("div",{...C,children:[Ae("audio",{ref:g,children:Ae(re,{src:e})}),Ae(Ke,{audioRef:g,fftSize:a,width:o,height:r,minDecibels:u,maxDecibels:d,colorMap:t,smoothingTimeConstant:l,onFrameUpdate:L,fillStyle:f,loop:c})]})}var ma={title:"Player",description:"A simple audio player component.",url:"",props:{src:{value:"string",description:"The source URL of the audio file.",required:!0,default:void 0},size:{value:"number",description:"The size of the player.",required:!1,default:void 0},color:{value:"string",description:"The color of the player.",required:!1,default:O.primary},autoplay:{value:"boolean",description:"Whether the audio should start playing automatically.",required:!1,default:!1},loop:{value:"boolean",description:"Whether the audio should loop.",required:!1,default:!1},showProgress:{value:"boolean",description:"Whether to show the progress bar.",required:!1,default:!0},showVolume:{value:"boolean",description:"Whether to show the volume control.",required:!1,default:!0},showNextPrevControls:{value:"boolean",description:"Whether to show the next and previous controls (used within ShufflePlayer).",required:!1,default:!1},audioRef:{value:"RefObject<HTMLAudioElement | null>",description:"A ref to the audio element.",required:!1,default:void 0},onNext:{value:"() => void",description:"Callback function for the next button. (used within ShufflePlayer)",required:!1,default:void 0},onPrev:{value:"() => void",description:"Callback function for the previous button. (used within ShufflePlayer)",required:!1,default:void 0}}};var La={title:"ShufflePlayer",description:"A simple audio player component with shuffle functionality.",url:"",props:{srcs:{value:"string[]",description:"An array of source URLs for the audio files.",required:!0,default:void 0},autoplay:{value:"boolean",description:"Whether the audio should start playing automatically.",required:!1,default:!1},color:{value:"string",description:"The color of the player.",required:!1,default:O.primary},showNextPrevControls:{value:"boolean",description:"Whether to show the next and previous controls.",required:!1,default:!0},showProgress:{value:"boolean",description:"Whether to show the progress bar.",required:!1,default:!0},showVolume:{value:"boolean",description:"Whether to show the volume control.",required:!1,default:!0},shuffle:{value:"boolean",description:"Whether to shuffle the audio files. If true, a random file will be played each time.",required:!1,default:!1}}};var xa={title:"Waveform",description:"A waveform component that visualizes audio data in a canvas element.",url:"",props:{src:{value:"string",description:"The source URL of the audio file to visualize. (internal unless CORS settings are configured)",required:!0,default:void 0},size:{value:"number",description:"The size of the canvas element in pixels.",required:!1,default:420},color:{value:"string",description:"The color of the waveform.",required:!1,default:"primary"},autoplay:{value:"boolean",description:"Whether to autoplay the audio when the component is mounted.",required:!1,default:!1},loop:{value:"boolean",description:"Whether to loop the audio playback.",required:!1,default:!1},showProgress:{value:"boolean",description:"Whether to show the progress of the audio playback.",required:!1,default:!1},showVolume:{value:"boolean",description:"Whether to show the volume control.",required:!1,default:!1},fftSize:{value:"number",description:"The size of the FFT (Fast Fourier Transform) used for audio analysis.",required:!1,default:2048},onLoad:{value:"() => void",description:"Callback function to be called when the audio is loaded.",required:!1,default:void 0},audioRef:{value:"RefObject<HTMLAudioElement | null> | null",description:"A reference to the HTML audio element. If not provided, a new ref will be created.",required:!1,default:null}}};var Ia={title:"Oscillator",description:"An oscillator component that generates sound waves based on gain and frequency.",url:"",props:{type:{value:"OscillatorType",description:"The type of oscillator wave (e.g., sine, square, sawtooth, triangle).",required:!1,default:"sine"},frequency:{value:"number",description:"The frequency of the oscillator in Hz.",required:!1,default:440},gain:{value:"number",description:"The default gain (volume) of the oscillator.",required:!1,default:.5},onPlayChange:{value:"(playing: boolean) => void",description:"Callback function to handle play/pause changes.",required:!1,default:void 0},isPlaying:{value:"boolean",description:"Whether the oscillator is currently playing sound.",required:!1,default:!1},onFrequencyChange:{value:"(frequency: number) => void",description:"Callback function to handle frequency changes.",required:!1,default:void 0},onGainChange:{value:"(gain: number) => void",description:"Callback function to handle gain changes.",required:!1,default:void 0}}};var ha={title:"Spectrogram",description:"A component that visualizes audio data as a spectrogram.",url:"",props:{src:{value:"string",description:"The source URL of the audio file to visualize.",required:!0,default:void 0},fftSize:{value:"number",description:"The size of the FFT (Fast Fourier Transform) used for audio analysis.",required:!1,default:1024},width:{value:"number | string",description:"The width of the spectrogram display.",required:!1,default:"100%"},height:{value:"number | string",description:"The height of the spectrogram display.",required:!1,default:"25%"},minDecibels:{value:"number",description:"The minimum decibel level for the spectrogram display.",required:!1,default:-100},maxDecibels:{value:"number",description:"The maximum decibel level for the spectrogram display.",required:!1,default:-25},colorMap:{value:"string[]",description:"An array of colors to use for the spectrogram visualization.",required:!1,default:["#111","#ff0000","#ffff00","#ffffff"]},smoothingTimeConstant:{value:"number",description:"The smoothing time constant for the analyser node.",required:!1,default:.8},onFrameUpdate:{value:"(data: Uint8Array) => void",description:"Callback function to handle frame updates with audio data.",required:!1,default:void 0},loop:{value:"boolean",description:"Whether to loop the audio playback.",required:!1,default:!1},fillStyle:{value:"string",description:"The fill style for the spectrogram canvas.",required:!1,default:void 0}}};var Ca={title:"AudioRecorder",description:"Record, preview, and download audio.",url:"",props:{waveColor:{value:"string",default:"rgb(236, 106, 177)",description:"The color of the waveform & preview.",required:!1},width:{value:"number",default:400,description:"The width of the audio recorder.",required:!1},height:{value:"number",default:80,description:"The height of the audio recorder.",required:!1}}};var ga={name:"AudioLooper",category:"Audio Components",description:"Multi-track loop recording and playback component with individual track controls",features:["Record multiple audio loops simultaneously","Individual track controls (play, pause, volume, clear)","Configurable loop duration (1-16 seconds)","Master volume control","Real-time progress visualization","Track management (add, remove, clear all)","Synchronized playback across all tracks"],props:{className:{type:"string",description:"CSS class name for styling",required:!1,default:void 0},maxTracks:{type:"number",description:"Maximum number of tracks allowed",required:!1,default:8},defaultLoopDuration:{type:"number",description:"Default loop duration in seconds",required:!1,default:4},color:{type:"string",description:"Primary color for UI elements",required:!1,default:"Colors.primary"}},usage:`import { AudioLooper } from "@clxrity/react-audio";
function MyComponent() {
return (
<AudioLooper
maxTracks={6}
defaultLoopDuration={8}
color="#ff6b9d"
/>
);
}`,examples:[{title:"Basic Looper",code:"<AudioLooper />"},{title:"Custom Configuration",code:`<AudioLooper
maxTracks={4}
defaultLoopDuration={2}
color="#00ff88"
/>`},{title:"Styled Looper",code:`<AudioLooper
className="my-looper"
maxTracks={12}
defaultLoopDuration={16}
/>`}]};var Sa={Player:ma,ShufflePlayer:La,Waveform:xa,Oscillator:Ia,Spectrogram:ha,AudioRecorder:Ca,AudioLooper:ga};export{ua as AudioLooper,oa as AudioRecorder,na as Oscillator,K as Player,da as ShufflePlayer,Ke as SpectroGramDisplay,pa as Spectrogram,ia as Waveform,Sa as components,Ee as useAudioAnalyser,ze as useAudioLooper,Ue as useAudioRecorder};
/*! Bundled license information:
lucide-react/dist/esm/shared/src/utils.js:
lucide-react/dist/esm/defaultAttributes.js:
lucide-react/dist/esm/Icon.js:
lucide-react/dist/esm/createLucideIcon.js:
lucide-react/dist/esm/icons/circle-stop.js:
lucide-react/dist/esm/icons/download.js:
lucide-react/dist/esm/icons/fast-forward.js:
lucide-react/dist/esm/icons/hourglass.js:
lucide-react/dist/esm/icons/loader-circle.js:
lucide-react/dist/esm/icons/mic.js:
lucide-react/dist/esm/icons/pause.js:
lucide-react/dist/esm/icons/play.js:
lucide-react/dist/esm/icons/plus.js:
lucide-react/dist/esm/icons/rewind.js:
lucide-react/dist/esm/icons/skip-back.js:
lucide-react/dist/esm/icons/skip-forward.js:
lucide-react/dist/esm/icons/square-square.js:
lucide-react/dist/esm/icons/square.js:
lucide-react/dist/esm/icons/trash-2.js:
lucide-react/dist/esm/icons/volume-1.js:
lucide-react/dist/esm/icons/volume-2.js:
lucide-react/dist/esm/icons/volume-x.js:
lucide-react/dist/esm/icons/x.js:
lucide-react/dist/esm/lucide-react.js:
(**
* @license lucide-react v0.541.0 - ISC
*
* This source code is licensed under the ISC license.
* See the LICENSE file in the root directory of this source tree.
*)
*/
//# sourceMappingURL=index.js.map