Giter Club home page Giter Club logo

wavesurfer.js's Introduction

logo wavesurfer.js

npm sponsor

Wavesurfer.js is an interactive waveform rendering and audio playback library, perfect for web applications. It leverages modern web technologies to provide a robust and visually engaging audio experience.

waveform screenshot

Getting started

Install and import the package:

npm install --save wavesurfer.js
import WaveSurfer from 'wavesurfer.js'

Alternatively, insert a UMD script tag which exports the library as a global WaveSurfer variable:

<script src="https://unpkg.com/wavesurfer.js@7"></script>

Create a wavesurfer instance and pass various options:

const wavesurfer = WaveSurfer.create({
  container: '#waveform',
  waveColor: '#4F4A85',
  progressColor: '#383351',
  url: '/audio.mp3',
})

To import one of the plugins, e.g. the Regions plugin:

import Regions from 'wavesurfer.js/dist/plugins/regions.esm.js'

Or as a script tag that will export WaveSurfer.Regions:

<script src="https://unpkg.com/wavesurfer.js@7/dist/plugins/regions.min.js"></script>

TypeScript types are included in the package, so there's no need to install @types/wavesurfer.js.

See more examples.

API reference

See the wavesurfer.js documentation on our website:

Plugins

We maintain a number of official plugins that add various extra features:

  • Regions – visual overlays and markers for regions of audio
  • Timeline – displays notches and time labels below the waveform
  • Minimap – a small waveform that serves as a scrollbar for the main waveform
  • Envelope – a graphical interface to add fade-in and -out effects and control volume
  • Record – records audio from the microphone and renders a waveform
  • Spectrogram – visualization of an audio frequency spectrum (written by @akreal)
  • Hover – shows a vertical line and timestmap on waveform hover

CSS styling

wavesurfer.js v7 is rendered into a Shadow DOM tree. This isolates its CSS from the rest of the web page. However, it's still possible to style various wavesurfer.js elements with CSS via the ::part() pseudo-selector. For example:

#waveform ::part(cursor):before {
  content: '🏄';
}
#waveform ::part(region) {
  font-family: fantasy;
}

You can see which elements you can style in the DOM inspector – they will have a part attribute. See this example to play around with styling.

Questions

Have a question about integrating wavesurfer.js on your website? Feel free to ask in our Discussions forum.

However, please keep in mind that this forum is dedicated to wavesurfer-specific questions. If you're new to JavaScript and need help with the general basics like importing NPM modules, please consider asking ChatGPT or StackOverflow first.

FAQ

I'm having CORS issues Wavesurfer fetches audio from the URL you specify in order to decode it. Make sure this URL allows fetching data from your domain. In browser JavaScript, you can only fetch data eithetr from the same domain or another domain if and only if that domain enables CORS. So if your audio file is on an external domain, make sure that domain sends the right Access-Control-Allow-Origin headers. There's nothing you can do about it from the requesting side (i.e. your JS code).
Does wavesurfer support large files? Since wavesurfer decodes audio entirely in the browser using Web Audio, large clips may fail to decode due to memory constraints. We recommend using pre-decoded peaks for large files (see this example). You can use a tool like bbc/audiowaveform to generate peaks.
What about streaming audio? Streaming audio is supported only with pre-decoded peaks and duration.
There is a mismatch between my audio and the waveform. How do I fix it? If you're using a VBR (variable bit rate) audio file, there might be a mismatch between the audio and the waveform. This can be fixed by converting your file to CBR (constant bit rate).

Alternatively, you can use the Web Audio shim which is more accurate.

How do I connect wavesurfer.js to Web Audio effects? Generally, wavesurfer.js doesn't aim to be a wrapper for all things Web Audio. It's just a player with a waveform visualization. It does allow connecting itself to a Web Audio graph by exporting its audio element (see this example) but nothign more than that. Please don't expect wavesurfer to be able to cut, add effects, or process your audio in any way.

v7 – a new TypeScript version

Wavesurfer.js v7 is a TypeScript rewrite of wavesurfer.js that brings several improvements:

  • Typed API for better development experience
  • Enhanced decoding and rendering performance
  • New and improved plugins

Upgrading from v6

Most options, events, and methods are similar to those in previous versions.

Notable differences

  • HTML audio playback by default (used to be an opt-in via backend: "MediaElement")
  • The Markers plugin is removed – you should use the Regions plugin with just a startTime.
  • No Microphone plugin – superseded by the new Record plugin with more features.
  • The Cursor plugin is replaced by the Hover plugin.

Removed options

  • audioContext, closeAudioContext, audioScriptProcessor
  • autoCenterImmediatelyautoCenter is now always immediate unless the audio is playing
  • backgroundColor, hideCursor – this can be easily set via CSS
  • mediaType – you should instead pass an entire media element in the media option. Example.
  • partialRender – done by default
  • pixelRatiowindow.devicePixelRatio is used by default
  • renderer – there's just one renderer for now, so no need for this option
  • responsive – responsiveness is enabled by default
  • scrollParent – the container will scroll if minPxPerSec is set to a higher value
  • skipLength – there's no skipForward and skipBackward methods anymore
  • splitChannelsOptions – you should now use splitChannels to pass the channel options. Pass height: 0 to hide a channel. See this example.
  • drawingContextAttributes, maxCanvasWidth, forceDecode – removed to reduce code complexity
  • xhr - please use fetchParams instead
  • barMinHeight - the minimum bar height is now 1 pixel by default

Removed methods

  • getFilters, setFilter – see the Web Audio example
  • drawBuffer – to redraw the waveform, use setOptions instead and pass new rendering options
  • cancelAjax – you can pass an AbortSignal in fetchParams
  • skipForward, skipBackward, setPlayEnd – can be implemented using setTime(time)
  • exportPCM is replaced with exportPeaks which returns arrays of floats
  • toggleMute is now called setMuted(true | false)
  • setHeight, setWaveColor, setCursorColor, etc. – use setOptions with the corresponding params instead. E.g., wavesurfer.setOptions({ height: 300, waveColor: '#abc' })

See the complete documentation of the new API.

Development

To get started with development, follow these steps:

  1. Install dev dependencies:
yarn
  1. Start the TypeScript compiler in watch mode and launch an HTTP server:
yarn start

This command will open http://localhost:9090 in your browser with live reload, allowing you to see the changes as you develop.

Tests

The tests are written in the Cypress framework. They are a mix of e2e and visual regression tests.

To run the test suite locally, first build the project:

yarn build

Then launch the tests:

yarn cypress

Feedback

We appreciate your feedback and contributions!

If you encounter any issues or have suggestions for improvements, please don't hesitate to post in our forum.

We hope you enjoy using wavesurfer.js and look forward to hearing about your experiences with the library!

wavesurfer.js's People

Contributors

agamemnus avatar akreal avatar binron avatar brian-byassee avatar chrisparton1991 avatar entonbiba avatar ffxsam avatar fluffywaffles avatar fzyukio avatar gintelllect avatar jabr avatar jagthedrummer avatar katspaugh avatar lorenzos avatar marizuccara avatar moritzvieli avatar mspae avatar mwise avatar n-st avatar nabiulin avatar naomiaro avatar nmgtn avatar osheroff avatar panda-go-panda avatar rgagnon24 avatar sundayz avatar tf avatar thijstriemstra avatar whenov avatar x-raym avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

wavesurfer.js's Issues

Trying to get Firefox Aurora running with wavesurfer.js

Hi katspaugh, cool library.

Question: have you had a chance to mess around with getting this running with Firefox? I know Web Audio API support isn't in the main branch yet, but it's already in Firefox Aurora so perhaps it’s a good time to look into it?

I haven’t succeeded in getting it running, but I found two things -- here -- involving renamed nodes:

diff --git a/src/webaudio.js b/src/webaudio.js
index 96b1f4a..8485331 100644
--- a/src/webaudio.js
+++ b/src/webaudio.js
@@ -11,7 +11,7 @@ WaveSurfer.WebAudio = {

     createScriptNode: function () {
         var my = this;
-        this.scriptNode = this.ac.createJavaScriptNode(256);
+        this.scriptNode = this.ac.createScriptProcessor(256);
         this.scriptNode.connect(this.ac.destination);
         this.scriptNode.onaudioprocess = function () {
             if (my.source && !my.isPaused()) {
@@ -25,7 +25,7 @@ WaveSurfer.WebAudio = {
      */
     createVolumeNode: function () {
         // Create gain node using the AudioContext
-        this.gainNode = this.ac.createGainNode();
+        this.gainNode = this.ac.createGain();

         // Add the gain node to the graph
         this.gainNode.connect(this.ac.destination);

Those two changes made some errors go away, but right now I’m getting this in the console:

[15:45:31.746] InvalidStateError: An attempt was made to use an object that is not, or is no longer, usable @ http://glyph.local/~pat/lingapp/js/lib/wavesurfer/src/wavesurfer.js:199

Moveable Markers?

Hi Katspaugh,

I LOVE this tool and I'm having a lot of fun playing with it. I'm working on a project using wavesurfer to look at a long audio file and then cut a section from it. That part's all easy - but I'm trying to make a dual range slider to control the "in" point and "out" point of the section I'm cutting/copying.

I use the green marker for in and the red for out, and have it set up to not allow more than one of each, and I have the time values for each go into the input boxes for "in" and "out". That's all good. But I can't seem to figure out how to MOVE a marker that has already been set. I'd like to be able to have the green marker move as soon as the value in the "in" input box is changed, so that its position on the waveform matches the value in the box.. is there a way to do this? I've spent hours playing with it and can't figure it out..

Thanks so much for making such a great tool!

Best, John

error handling when giving wavesurfer no container

i kept getting this error when making a wave but not initing it with a container:

TypeError: Cannot read property 'clientWidth' of null

i'm pretty sure now this is because the default container in the source code is null. this doesn't affect me, but i figured maybe i'd let you know in case you want wavesurfer to handle this more cleanly than just erroring?

Stopping cursor at a specified position.

Thanks for this plugin.

I can play a section of a file using the backend play(start, end) method, but I'm having trouble figuring out how to stop the cursor as well.

Max pcm value in audio buffer

Hello,

I noticed that waveform is shown such that maximum pcm value in the audio buffer would occupy the whole height of the svg, thus, audio that contains only quiet sounds will look similar to the one that contains loud sounds. I think sometimes it's useful to keep max value at 1.0 instead of using max value of audio buffer. I am not sure if this is a valid use case. Let me know if my explanation does not make any sense!

Thanks!

stop() doesn't always update waveform correctly

Hello,

I am not sure whether it's a bug or I am using stop() incorrectly. I am calling wavesurfer.stop() when user clicks on a button and i expect play position of a waveform to go back to the beginning, however, the marker does not always go back to the start of a waveform (although audio always stops playing). It could be that onaudioprocess (https://github.com/katspaugh/wavesurfer.js/blob/master/src/webaudio.js#L37) gets called in between "this.playAt(0)" and "this.pause()" (https://github.com/katspaugh/wavesurfer.js/blob/master/src/wavesurfer.js#L89).

loading via "bindDragNDrop" emits no loading events

or at least not from my tests. (but bindDragNDrop works beautifully now :D)

this does not emit console logs (after dropping waveform and confirming it loaded successfully in the browser):

wave.bindDragNDrop($(selector+' .waveform')[0]);

  // progress bar
  wave.on('loading', function(percent, xhr) {
    console.log(percent);
    $(selector+' .loadText').hide();
    console.log($(selector+' .loadText'));
  });

this does emit console logs:

  // progress bar
  wave.on('loading', function(percent, xhr) {
    console.log(percent);
    $(selector+' .loadText').hide();
    console.log($(selector+' .loadText'));
  });
  wave.load('songs/the sky.mp3');

webkit prefix in webkitRequestAnimationFrame (webaudio.js)

Since RequestAnimationFrame is also available in browsers other than Chrome, could you please add a check in webaudio.js(line 28), something like:
window.RequestAnimationFrame = window.RequestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame

Node/V8 integration possible?

I'm just wondering whether we can use the audio APis to generate a static waveform image using Node.js. For long audio files, the waveform generation takes a long time client side, so I am wondering if it's possible to move the processing to the server side, so that the audio can be pre-processed.

Coloring Progress

Great little lib! I only wish that it would color the waveform as it progressed
Screen shot 2012-12-10 at 3.17.53 AM.png

Cursor reached a mark

Hi,

How is it possible to know or throw event when the playing cursor has reached a mark?

Thanks

Current position marker stops updating

First of all, I forgot to say in another issue how great your plugin is!!! =)

Now onto the issue I am having. After I open open your example, play the audio/pause audio multiple times and then leave it for a while (sometimes less than 30 minutes, sometimes more) and try to play it again, the audio does play but the marker that shows current position does not move. By putting breakpoints and looking at it, it seems like wavesurfer.onAudioProcess does not get called anymore.

renderer : 'SVG' causes other javascript to lag.

Hi it's me again XD so I was able to get SVG to render the waveform at 100px per second. however the SVG renderer doesn't result in an image that's as sharp as the canvas renderer but the main problem is when i try to play the music and also run other javascript, it results in a massive amount of lag for my other javascript. this didn't happen when I was using the Canvas renderer. Thanks.

PS: the music itself didn't lag but everything else did

getting length of song?

I dont really see any methods to get the length of the song since i would like to make the size of my container change accordingly with the length of the song. Would be very helpful if there is a method to provide the length of the song i'm sure there is one internally somewhere thanks. :)

Playback starts after skip back/forward

Calling wavesurfer.skipBackward() causes playback to start immediately after moving. It would be better IMHO if the current playing state was observed - i.e. if the track is currently paused, after seeking it should remain paused.

Looks like a really good project.

Remote audio link not compatible

Hey i tried out, this is fantastic but still remote url audio is not working. I think it could be fixed easy by you. THANKS for such a project.

Visual segmentation

Add ability to create visual segments of audio. No UI, just programmatically (for use with ELAN markup, for instance). Segments should have customizable color overlay.

Inspiration: this nice demo.

Large MP3 files cause DOM Exception 12

Hi there,

I absolutely love this plugin. It works great when I try to play small MP3 files.

However, when I try to load a larger MP3 file (51 MB), I get an JS error: DOM Exception 12.
The MP3 file seems to load fine in the beginning, but in the end it's slowing down (the line which indicates that it's loading moves at a much slower rate). My Chrome browser tab also crashes at the end (gives me a purple error message).

This is the error I'm getting:

Uncaught Error: SyntaxError: DOM Exception 12 webaudio.js:66
WaveSurfer.WebAudio.loadData webaudio.js:66
(anonymous function)

When I'm looking at webaudio.js it seems to be an issue with the decodeAudioData() method.

Is this a known issue? And how can I fix this problem?

Help would be appreciated, since I'm stuck with my project right now.

Thanks in advance!

Question: how to clear waveform

Hello,

It could be a silly question but I can't seem to figure it out.
Say I loaded buffers and I have a waveform, then I would like to clear waveform image, show it as if nothing is loaded (without reinitializing wavesurfer), how can I do it?

Thanks!

Load new wave?

Hi,

Thanks for this great plugin.
After loading a waveform into canvas, I can't load a new waveform.
I try to clear the canvas, and then use wavesurfer.load(url) again, but I get the loading indication and then an empty canvas.
I also tried to create a new wavesurfer instance but it doesn't work as well.
How can it be done?

HTML5 Audio element fallback

Would it be possible to play the audio through an audio element and do only the visualization through canvas?

This would be far more accessible and gives you the option to use the HTML5 audio API.

drag and drop isn't working in chrome


  wave.init({
    container: document.querySelector("#"+id),
    waveColor: 'violet',
    progressColor: 'purple',
    renderer: 'SVG',
    audioContext: context
  });
wave.bindDragNDrop();

I drag an audio file onto the page, and chrome goes to the page of the dropped file's url on my system, like so: "file:///home/kane/projects/beatfn-music/Chasing-The-Sun-Hardwell-Remix.mp3"
rather than loading it into wave.

i feel like i'm missing something - any suggestions or pointers?

Presetting markers

So I have stored two positions marked using the following code:

startTime = wavesurfer.drawer.markers["start"].position
endTime   = wavesurfer.drawer.markers["end"].position
// Storing logic...

When I load wavesurfer I would like to be able to mark these two positions again, but can't find a way of doing it.
I tried creating marker objects and adding them to the wavesurfer.drawer.markers object, but couldn't find a way to calculate the percentage property (since I don't know when the audio has been loaded).

Is there a way of doing this easily, or could this perhaps be added as a feature?

ability to click and drag to move the cursor?

it seems like natural behavior, and what people are used to from things like music players and soundcloud.

edit: hmmm after thinking about it i realized i can implement this in my app with an onkeyevent bound to the div holding the waveform, and then calling seek from the handler. it would still be kinda cool if this could be implemented internally.

... for that matter, a marker on hover would be cool too. same story.

Mobile Browser Performance

Hi,

Have you tried to use wavesurfer on a mobile device? I'm trying to get my app working on an Retina iPad (iOS6). Functionally everything is working fine but re-rendering the entire canvas to display the progress every audio frame is killing performance, making the app unusable.

Unfortunately my canvas expertise is limited so I have not come across a solution for this that I can share. Do you have any plans or ideas for performance improvements particularly with the drawer?

Best,
Stan

Plugin idea: Silence finder

Hi katspaugh,

This may be offtopic for you at the current stage of the project, in any case I might see if I can pull this idea off myself, but I thought I’d throw the idea out there.

What about a Silence Detection plugin? This would be very useful in transcription applications, where you could play a phrase, transcribe, play another phrase, transcribe, etc.

There are analogies in other pieces of software; I believe ELAN can do it and I know there’s a plugin in Audacity that adds labels at silences:

http://manual.audacityteam.org/man/Silence_Finder_and_Sound_Finder#silence

I once wrote a simple way to do this in the old Mozilla Audio Data API, which I documented here:

http://stackoverflow.com/questions/11057429/something-like-mozaudioavailable-with-webkits-audio-api

And there is a response from Boris Smus (who wrote a book on the Web Audio API) on how it might be approached in the new standard.

One question is how one would go about handling the issue of buffering a large audio file, but I suppose you must have figured that out since you’re drawing the waveform of large files already.

Thanks,
Pat

ability to cancel a buffer load

in the documentation:

"

  • loading – fires continuously when loading via XHR. Callback recieves loading progress in percents
    "

is there a way to cancel a buffer load once it's started? it's something i was hoping to be able to do and wasn't sure if you had plans for it. it's particularly useful in the case where you're streaming audio from the cloud - ie dropbox, s3, etc

(ps this library is incredible, thanks so much for making it!)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.