Convert Figma logo to code with AI

naomiaro logowaveform-playlist

Multitrack Web Audio editor and player with canvas waveform preview. Set cues, fades and shift multiple tracks in time. Record audio tracks or provide audio annotations. Export your mix to AudioBuffer or WAV! Add effects from Tone.js. Project inspired by Audacity.

1,452
285
1,452
47

Top Related Projects

JavaScript UI component for interacting with audio waveforms

Audio waveform player

Quick Overview

Waveform-playlist is a multitrack web audio editor and player built with Web Audio API and React. It allows users to create, edit, and play audio tracks in a browser-based interface, offering features like track mixing, volume control, and waveform visualization.

Pros

  • Browser-based audio editing without the need for native applications
  • Supports multiple audio tracks with individual controls
  • Provides waveform visualization for easy audio navigation
  • Built with modern web technologies (React and Web Audio API)

Cons

  • Limited advanced audio editing features compared to professional desktop software
  • Dependent on browser support for Web Audio API
  • May have performance issues with a large number of tracks or long audio files
  • Documentation could be more comprehensive for advanced usage

Code Examples

  1. Creating a new playlist:
import Playlist from 'waveform-playlist';

const playlist = Playlist({
  container: document.getElementById('playlist'),
  timescale: true,
  state: 'cursor',
  samplesPerPixel: 1000,
  mono: true,
  waveHeight: 100,
  colors: {
    waveOutline: '#E0EFF1',
    timeColor: 'grey',
    fadeColor: 'black'
  }
});
  1. Adding a track to the playlist:
playlist.load([
  {
    src: 'path/to/audio/file.mp3',
    name: 'My Audio Track',
    gain: 0.5
  }
]).then(function() {
  // playlist is ready
});
  1. Controlling playback:
// Play the playlist
playlist.play();

// Pause the playlist
playlist.pause();

// Seek to a specific time (in seconds)
playlist.seek(30);

Getting Started

To use waveform-playlist in your project:

  1. Install the package:

    npm install waveform-playlist
    
  2. Import and initialize in your React component:

    import React, { useEffect, useRef } from 'react';
    import Playlist from 'waveform-playlist';
    
    function AudioEditor() {
      const playlistRef = useRef(null);
    
      useEffect(() => {
        const playlist = Playlist({
          container: playlistRef.current,
          // ... other options
        });
    
        // Load tracks, set up event listeners, etc.
      }, []);
    
      return <div ref={playlistRef}></div>;
    }
    
    export default AudioEditor;
    
  3. Customize the playlist with your desired options and add tracks as needed.

Competitor Comparisons

JavaScript UI component for interacting with audio waveforms

Pros of peaks.js

  • More actively maintained with frequent updates and bug fixes
  • Better documentation and examples for easier integration
  • Supports both canvas and WebAudio API for broader browser compatibility

Cons of peaks.js

  • Less flexible for complex audio editing tasks
  • Limited built-in features compared to waveform-playlist
  • Steeper learning curve for advanced customization

Code Comparison

peaks.js:

var peaksInstance = Peaks.init({
  container: document.getElementById('waveform-container'),
  mediaElement: document.querySelector('audio'),
  dataUri: 'path/to/waveform.json'
});

waveform-playlist:

var playlist = WaveformPlaylist.init({
  container: document.getElementById('playlist'),
  timescale: true,
  state: 'cursor',
  samplesPerPixel: 1000,
  waveHeight: 100,
  tracks: [{ src: 'path/to/audio.mp3' }]
});

Both libraries offer ways to initialize and render waveforms, but waveform-playlist provides more options for customization in its initial setup. peaks.js focuses on simplicity and ease of use, while waveform-playlist offers more advanced features for audio editing and manipulation.

Audio waveform player

Pros of wavesurfer.js

  • More extensive documentation and examples
  • Wider range of features, including support for various audio formats and streaming
  • Larger community and more frequent updates

Cons of wavesurfer.js

  • Steeper learning curve due to more complex API
  • Heavier file size, which may impact page load times
  • Less focus on multi-track editing capabilities

Code Comparison

wavesurfer.js:

const wavesurfer = WaveSurfer.create({
    container: '#waveform',
    waveColor: 'violet',
    progressColor: 'purple'
});
wavesurfer.load('audio.mp3');

waveform-playlist:

var playlist = WaveformPlaylist.init({
    container: document.getElementById("playlist"),
    timescale: true,
    state: 'cursor',
    samplesPerPixel: 1000,
    waveHeight: 100,
    tracks: [{src: "audio.mp3"}]
});

Both libraries offer waveform visualization and audio playback, but wavesurfer.js provides a more straightforward setup for single-track scenarios, while waveform-playlist is geared towards multi-track editing and playlist management. wavesurfer.js offers more customization options out-of-the-box, whereas waveform-playlist focuses on providing a complete multi-track editing solution with less initial setup required.

Convert Figma logo designs to code with AI

Visual Copilot

Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.

Try Visual Copilot

README

npm

Sponsors

Become a sponsor

Waveform Playlist

Inspired by Audacity, this project is a multiple track playlist editor written in ES2015 using the Web Audio API.

Load tracks and set cues (track cue in, cue out), fades (track fade in, fade out) and track start/end times within the playlist. I've written up some demos on github for the different audio fade types in the project.

Screenshot (code for picture shown can be found in ghpages/_examples/04stemtracks.html)

Screenshot (code for picture shown can be found in ghpages/_examples/13annotations.html)

Browser Support

Waveform Playlist requires webaudio in the browser to function correctly: Can I Use?

Installation

npm install waveform-playlist --save

Hate npm? Check Unpkg: https://unpkg.com/browse/waveform-playlist/

  • If you want to download and run the already compiled website, navigate to folder /dist and run python -m SimpleHTTPServer 8000. The website will be available at localhost:8000/waveform-playlist.

Basic Usage

https://github.com/naomiaro/waveform-playlist/blob/main/examples/basic-html/

https://github.com/naomiaro/waveform-playlist/tree/main/examples/basic-express/

import WaveformPlaylist from "waveform-playlist";

var playlist = WaveformPlaylist({
  samplesPerPixel: 3000,
  mono: true,
  waveHeight: 70,
  container: document.getElementById("playlist"),
  state: "cursor",
  colors: {
    waveOutlineColor: "#E0EFF1",
    timeColor: "grey",
    fadeColor: "black",
  },
  controls: {
    show: false,
    width: 150,
  },
  zoomLevels: [500, 1000, 3000, 5000],
});

playlist
  .load([
    {
      src: "media/audio/Vocals30.mp3",
      name: "Vocals",
      gain: 0.5,
    },
    {
      src: "media/audio/BassDrums30.mp3",
      name: "Drums",
      start: 8.5,
      fadeIn: {
        duration: 0.5,
      },
      fadeOut: {
        shape: "logarithmic",
        duration: 0.5,
      },
    },
    {
      src: "media/audio/Guitar30.mp3",
      name: "Guitar",
      start: 23.5,
      fadeOut: {
        shape: "linear",
        duration: 0.5,
      },
      cuein: 15,
    },
  ])
  .then(function () {
    // can do stuff with the playlist.
  });

Playlist Options

var options = {
  // webaudio api AudioContext
  ac: new (window.AudioContext || window.webkitAudioContext)(),

  // DOM container element REQUIRED
  container: document.getElementById("playlist"),

  // sample rate of the project. (used for correct peaks rendering)
  sampleRate: new (
    window.AudioContext || window.webkitAudioContext
  ).sampleRate(),

  // number of audio samples per waveform peak.
  // must be an entry in option: zoomLevels.
  samplesPerPixel: 4096,

  // whether to draw multiple channels or combine them.
  mono: true,

  // enables "exclusive solo" where solo switches between tracks
  exclSolo: false,

  // default fade curve type.
  fadeType: "logarithmic", // (logarithmic | linear | sCurve | exponential)

  // whether or not to include the time measure.
  timescale: false,

  // control panel on left side of waveform
  controls: {
    // whether or not to include the track controls
    show: false,

    // width of controls in pixels
    width: 150,

    // whether to render the widget or not in the controls panel.
    widgets: {
      // Mute & solo button widget
      muteOrSolo: true,

      // Volume slider
      volume: true,

      // Stereo pan slider
      stereoPan: true,

      // Collapse track button
      collapse: true,

      // Remove track button
      remove: true,
    },
  },

  colors: {
    // color of the wave background
    waveOutlineColor: "white",

    // color of the time ticks on the canvas
    timeColor: "grey",

    // color of the fade drawn on canvas
    fadeColor: "black",
  },

  // height in pixels of each canvas element a waveform is on.
  waveHeight: 128,

  // width in pixels of waveform bars.
  barWidth: 1,

  // spacing in pixels between waveform bars.
  barGap: 0,

  // interaction state of the playlist
  // (cursor | select | fadein | fadeout | shift)
  state: "cursor",

  // (line | fill)
  seekStyle: "line",

  // Array of zoom levels in samples per pixel.
  // Smaller numbers have a greater zoom in.
  zoomLevels: [512, 1024, 2048, 4096],

  // Whether to automatically scroll the waveform while playing
  isAutomaticScroll: false,

  // configuration object for the annotations add on.
  annotationList: {
    // Array of annotations in [Aeneas](https://github.com/readbeyond/aeneas) JSON format
    annotations: [],

    // Whether the annotation texts will be in updateable contenteditable html elements
    editable: false,

    // User defined functions which can manipulate the loaded annotations
    controls: [
      {
        // class names for generated <i> tag separated by '.'
        class: "fa.fa-minus",

        // title attribute for the generated <i> tag
        title: "Reduce annotation end by 0.010s",

        // function which acts on the given annotation row
        // when the corresponding <i> is clicked.
        action: (annotation, i, annotations, opts) => {
          // @param Object annotation - current annotation
          // @param Number i - index of annotation
          // @param Array annotations - array of annotations in the playlist
          // @param Object opts - configuration options available
          //      - opts.linkEndpoints
        },
      },
    ],

    // If false when clicking an annotation id segment
    // playback will stop after segment completion.
    isContinuousPlay: false,

    // If true annotation endpoints will remain linked when dragged
    // if they were the same value before dragging started.
    linkEndpoints: false,

    // pass a custom function which will receive the mastergainnode for this playlist and the audio context's destination.
    // if you pass a function, you must connect these two nodes to hear sound at minimum.
    // if you need to clean something up when the graph is disposed, return a cleanup function. Waveform Playlist will cleanup the nodes passed as arguments.
    effects: function (masterGainNode, destination, isOffline) {
      // analyser nodes don't work offline.
      if (!isOffline) masterGainNode.connect(analyser);
      masterGainNode.connect(destination);

      // return function cleanup() {
      //   // if you create webaudio nodes that need to be cleaned up do that here
      //   // see the track effects example.
      // };
    },
  },
};

Track Options

{
  // a media path for XHR, a Blob, a File, or an AudioBuffer object.
  src: 'media/audio/BassDrums30.mp3',

  // name that will display in the playlist control panel.
  name: 'Drums',

  // volume level of the track between [0-1]
  gain: 1,

  // whether the track should initially be muted.
  muted: false,

  // whether the track should initially be soloed.
  soloed: false,

  // time in seconds relative to the playlist
  // ex (track will start after 8.5 seconds)
  // DEFAULT 0 - track starts at beginning of playlist
  start: 8.5,

  // track fade in details
  fadeIn: {
    // fade curve shape
    // (logarithmic | linear | sCurve | exponential)
    shape: 'logarithmic',

    // length of fade starting from the beginning of this track, in seconds.
    duration: 0.5,
  },

  // track fade out details
  fadeOut: {
    // fade curve shape
    // (logarithmic | linear | sCurve | exponential)
    shape: 'logarithmic',

    //length of fade which reaches the end of this track, in seconds.
    duration: 0.5,
  }

  // where the waveform for this track should begin from
  // ex (Waveform will begin 15 seconds into this track)
  // DEFAULT start at the beginning - 0 seconds
  cuein: 15,

  // where the waveform for this track should end
  // ex (Waveform will end at 30 second into this track)
  // DEFAULT duration of the track
  cueout: 30,

  // custom class for unique track styling
  customClass: 'vocals',

  // custom background-color for the canvas-drawn waveform
  waveOutlineColor: '#f3f3f3',

  // interaction states allowed on this track.
  // DEFAULT - all true
  states: {
    cursor: true,
    fadein: true,
    fadeout: true,
    select: true,
    shift: true,
  },

  // pre-selected section on track.
  // ONLY ONE selection is permitted in a list of tracks, will take most recently set if multiple passed.
  // This track is marked as 'active'
  selected: {
    // start time of selection in seconds, relative to the playlist
    start: 5,

    // end time of selection in seconds, relative to the playlist
    end: 15,
  },

  // value from -1 (full left pan) to 1 (full right pan)
  stereoPan: 0,

  // pass a custom function which will receive the last graphnode for this track and the mastergainnode.
  // if you pass a function, you must connect these two nodes to hear sound at minimum.
  // if you need to clean something up when the graph is disposed, return a cleanup function. Waveform Playlist will cleanup the nodes passed as arguments.
  effects: function(graphEnd, masterGainNode, isOffline) {
    var reverb = new Tone.Reverb(1.2);

    Tone.connect(graphEnd, reverb);
    Tone.connect(reverb, masterGainNode);

    return function cleanup() {
      reverb.disconnect();
      reverb.dispose();
    }
  }
}

Playlist Events

Waveform Playlist uses an instance of event-emitter to send & receive messages from the playlist.

import EventEmitter from "event-emitter";
import WaveformPlaylist from "waveform-playlist";

var playlist = WaveformPlaylist(
  {
    container: document.getElementById("playlist"),
  },

  // you can pass your own event emitter
  EventEmitter()
);

// retrieves the event emitter the playlist is using.
var ee = playlist.getEventEmitter();

An example of using the event emitter to control the playlist can be found in /dist/js/examples/emitter.js

Events to Invoke

eventargumentsdescription
playstart:optional, end:optionalStarts playout of the playlist. Takes optional Number parameters in seconds start and end to play just an audio segment. start can be passed without an end to play to the end of the track.
pausenonePauses playout of the playlist.
stopnoneStops playout of the playlist.
rewindnoneStops playout if playlist is playing, resets cursor to the beginning of the playlist.
fastforwardnoneStops playout if playlist is playing, resets cursor to the end of the playlist.
clearnoneStops playout if playlist is playing, removes all tracks from the playlist.
recordnoneStarts recording an audio track. Begins playout of other tracks in playlist if there are any.
zoominnoneChanges zoom level to the next smallest entry (if one exists) from the array zoomLevels.
zoomoutnoneChanges zoom level to the next largest entry (if one exists) from the array zoomLevels.
trimnoneTrims currently active track to the cursor selection.
statechangecursor / select / fadein / fadeout / shiftChanges interaction state to the state given.
fadetypelogarithmic / linear / sCurve / exponentialChanges playlist default fade type.
newtrackFileLoads File object into the playlist.
volumechangevolume, trackSet volume of track to volume (0-100)
mastervolumechangevolumeSet a new master volume volume (0-100)
selectstart, end, track:optionalSeek to the start time or start/end selection optionally with active track track.
startaudiorenderingwav / bufferRequest for a downloadable file or web Audio buffer that represent the current work
automaticscrolltrue/falseChange property isAutomaticScroll.
continuousplaytrue/falseChange property isContinuousPlay.
linkendpointstrue/falseChange property linkEndpoints.
annotationsrequestnoneRequests to download the annotations to a json file.
stereopanpanvalue, trackSet pan value of track to panvalue (-1-1)

Events to Listen to

eventargumentsdescription
selectstart, end, trackCursor selection has occurred from start to end with active Track track.
timeupdateplaybackPositionSends current position of playout playbackPosition in seconds.
scrollscrollLeftSends current position of scroll scrollLeft in seconds.
statechangestateSends current interaction state state.
shiftdeltaTime, trackSends deltaTime in seconds change for Track track
mutetrackMute button has been pressed for track
solotrackSolo button has been pressed for track
removeTracktrackRemove button has been pressed for track
changeTrackViewtrack, optsCollapse button has been pressed for track
volumechangevolume, trackVolume of track has changed to volume (0-100)
mastervolumechangevolumeMaster volume of the playlist has changed to volume (0-100)
audiorequeststatechangestate, srcLoading audio src (string or File) is now in state state (Number)
loadprogresspercent, srcLoading audio src has loaded percent percent (0-100)
audiosourcesloadednoneAudio decoding has finished for all tracks
audiosourcesrenderednoneTracks are rendered to the playlist
audiosourceserrorerrError thrown while loading tracks
finishednoneEvent fired when cursor ( while playing ) reaches the end (maximum duration)
audiorenderingstartingofflineCtx, setUpPromiseArrayEvent fired after the OfflineAudioContext is created before any rendering begins. If any setup is async before offline redering, push a promise to the setUpPromiseArray.
audiorenderingfinishedtype, dataReturn the result of the rendering in the desired format. type can be buffer or wav and can be used to dertermine the data type. When type is wav, data is a blob object that represent the wav file.
stereopanpanvalue, trackPan value of track has been changed to panvalue

Tests

npm test

Development without example changes

npm install && npm start

This will install dependencies and start the webpack server.

Development with example changes

gem install jekyll

Jekyll is needed if changes to the example pages will be done.

npm install && npm run dev

This will build and watch the jekyll site and startup the webpack dev server.

Credits

Originally created for the Airtime project at Sourcefabric

The annotation plugin has been sponsored by a fond Italian TED volunteer transcriber hoping to make the transcription process of TEDx talks easier and more fun.

Books

Currently writing: Mastering Tone.js. Get notified by Leanpub when I publish.

License

MIT License

NPM DownloadsLast 30 Days