npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@educandu/multitrack-audio-player

v1.0.3

Published

A multitrack audio player using the Web Audio API

Downloads

435

Readme

multitrack-audio-player

codecov

A multitrack audio player using the Web Audio API

Prerequisites

  • node.js ^20.0.0
  • optional: globally installed gulp: npm i -g gulp-cli

The output of this repository is an npm package (@educandu/multitrack-audio-player).

Installation

$ yarn add @educandu/multitrack-audio-player

Usage

import { MultitrackAudioPlayer, TrackGroup, Track, ... } from '@educandu/multitrack-audio-player';

Low level API

Track

The Track class is the main building block of this library and represents a single playable audio file.

// Minimal example for creating a new track:
const track = new Track({ sourceUrl: 'https://somedomain.com/some-sound.mp3' });

// Full example for creating a new track:
const track = new Track({
  // Mandatory, has to be a valid URL:
  sourceUrl: 'https://somedomain.com/some-sound.mp3',
  // Optional, has to be an array of two floats between 0 and 1 that indicate
  // the range withing the media file that should be played (0 means the first sample,
  // 1 means the last sample of the sound file). Default: [0, 1]
  playbackRange = [0.25, 0.75],
  // Optional, has to be an object with two fields:
  // * `gain` (float between 0 and 1) that stands for the volume between 0% and 100%.
  // * `mute` (boolean), if set to `true`, playback of this track will be muted.
  // Default: { gain: 1, mute: false }
  gainParams = { gain: 0.5, mute: false },
  // Optional, will be used as a factor when calculating the actual gain of the track.
  masterGain = 1,
  // Optional, can be used to associate custom data with individual tracks. Default: {}
  customProps: { key: 'some-key', name: 'My track', usage: 'internal' },
  // Optional, will be used to decode the audio file, can be replaced
  // by a custom implementation.
  mediaDecoder = new MediaDecoder(),
  // Optional, will be used to download the audio file, can be replaced
  // by a custom implementation.
  mediaDownloader = new MediaDownloader(),
  // Optional, will be used to retrieve an `AudioContext` that is ready to be used,
  // can be replaced by a custom implementation.
  audioContextProvider = new AudioContextProvider(),
  // Optional, will be called each time the track's `state` property has changed.
  onStateChanged = (state, error) => { console.log(error ?? state); },
  // Optional, will be called each time the track's `playState` property has changed.
  onPlayStateChanged = playState => { console.log(playState); }
});

// Methods:
track.initialize(); // Waits for the audio context. Has to be called before loading.
track.load(); // Downloads and decodes the media file. Has to be called before any playback.
track.start(); // Starts at the current position, if not already playing.
track.start(5.5); // Starts the track 5.5 seconds into the media.
track.pause(); // Pauses the track at the current position.
track.stop(); // Stops the track at the current position, equivalent to calling `track.pause()`.
track.stop(true); // Stops the track and moves to the very end of the media.
track.dispose(); // Disposes this instance, no further calls should be made after this.

// Read-only properties:
console.log(track.customProps); // Any custom data associated with this track.
console.log(track.error); // The error in case the state of this track is 'faulted'.
console.log(track.sourceUrl); // The url of the loaded sound file.
console.log(track.state); // The track state.
console.log(track.playState); // The track's play state.
console.log(track.duration); // The track's duration as a float in seconds.
console.log(track.playbackRange); // The track's playback range.

// Read-write properties:
track.position = 3.75; // Sets the track's current playback position.
track.gainParams = { gain: 0.5, mute: false }; // Sets the track's gain params.
track.masterGain = 1; // Sets the track's master gain.

// Example for reading the current time code:
setInterval(() => console.log(track.position), 100);

// Example for changing the volume to 50%:
track.gainParams = { ...track.gainParams, gain: 0.5 };

TrackGroup

The TrackGroup class wraps a collection of tracks while providing an API (mostly) identical to a single track. It manages state, play state and volume coordination between the tracks, including solo state. It also adds options for automatic rewinding and looping.

// Example for creating a new track group:
const trackGroup = new TrackGroup({
  // Mandatory, the track configuration
  trackConfiguration: {
    // Tracks with their initial configuration
    tracks: [
      {
        sourceUrl: 'https://somedomain.com/some-sound.mp3',
        playbackRange: [0, 1],
        gainParams: { gain: 0.5, mute: false },
        customProps: { name: 'First track' }
      },
      {
        sourceUrl: 'https://somedomain.com/some-other-sound.mp3',
        playbackRange: [0, 1],
        gainParams: { gain: 0.75, mute: false },
        customProps: { name: 'Second track' }
      },
    ],
    // Determines, which track should play solo initially (-1 for none)
    soloTrackIndex: -1
  },
  // Optional, will automatically start from the beginning, when the end of the
  // main track is reached (Play state will remain `started`). Default: false
  loop: true,
  // Optional, will automatically start from the beginning, when `start` is called
  // after the track has been played previously unto the very end. Default: false
  autoRewind: true,
  // Optional, has to be an object with two fields:
  // * `gain` (float between 0 and 1) that stands for the volume between 0% and 100%.
  // * `mute` (boolean), if set to `true`, playback of this track will be muted.
  // Default: { gain: 1, mute: false }
  gainParams = { gain: 0.5, mute: false },
  // Optional, will be used to decode the audio file, can be replaced
  // by a custom implementation.
  mediaDecoder = new MediaDecoder(),
  // Optional, will be used to download the audio file, can be replaced
  // by a custom implementation.
  mediaDownloader = new MediaDownloader(),
  // Optional, will be used to retrieve an `AudioContext` that is ready to be used,
  // can be replaced by a custom implementation.
  audioContextProvider = new AudioContextProvider(),
  // Optional, will be called each time the track group's `state` property has changed.
  onStateChanged = (state, error) => { console.log(error ?? state); },
  // Optional, will be called each time the track group's `playState` property has changed.
  onPlayStateChanged = playState => { console.log(playState); }
});

// Example for changing the volume to 50% in the second track:
trackGroup.tracks[1].gainParams = { ...track.gainParams, gain: 0.5 };

// Example for setting the second track as the solo track:
trackGroup.soloTrackIndex = 1;

High level API

MultitrackAudioPlayer

The MultitrackAudioPlayer class wraps a TrackGroup and adds a clock with change notifications on the current playback position as well as an option for automatic initialization and loading on top. In most cases this is the API that should be used by consumers of this library.

// Example for creating a new player:
const player = new MultitrackAudioPlayer({
  // Mandatory, the track configuration
  trackConfiguration: {
    // Tracks with their initial configuration
    tracks: [
      {
        sourceUrl: 'https://somedomain.com/some-sound.mp3',
        playbackRange: [0, 1],
        gainParams: { gain: 0.5, mute: false },
        customProps: { name: 'First track' }
      },
      {
        sourceUrl: 'https://somedomain.com/some-other-sound.mp3',
        playbackRange: [0, 1],
        gainParams: { gain: 0.75, mute: false },
        customProps: { name: 'Second track' }
      },
    ],
    // Determines, which track should play solo initially (-1 for none)
    soloTrackIndex: -1
  },
  // Optional (default: false), will immediately start waiting for the audio context,
  // without explicit call to the `initialize` function. Consumers nevertheless
  // have to wait until the `state` changes to `initialized` before calling `load`.
  autoInitialize: true,
  // Optional (default: false), will immediately start loading the tracks after initialization,
  // without explicit call to the `load` function. Consumers nevertheless have
  // to wait until the `state` changes to `ready` before starting playback.
  autoLoad: true,
  // Optional, will automatically start from the beginning, when `start` is called
  // after the track has been played previously unto the very end. Default: false
  loop: true,
  // Optional, will automatically start from the beginning, when the end of the
  // main track is reached (Play state will remain `started`). Default: false
  autoRewind: true,
  // Optional, has to be an object with two fields:
  // * `gain` (float between 0 and 1) that stands for the volume between 0% and 100%.
  // * `mute` (boolean), if set to `true`, playback of this track will be muted.
  // Default: { gain: 1, mute: false }
  gainParams = { gain: 0.5, mute: false },
  // Optional, will be used to decode the audio file, can be replaced
  // by a custom implementation.
  mediaDecoder = new MediaDecoder(),
  // Optional, will be used to download the audio file, can be replaced
  // by a custom implementation.
  mediaDownloader = new MediaDownloader(),
  // Optional, will be used to retrieve an `AudioContext` that is ready to be used,
  // can be replaced by a custom implementation.
  audioContextProvider = new AudioContextProvider(),
  // Optional, will be called each time the track group's `state` property has changed.
  onStateChanged = (state, error) => { console.log(error ?? state); },
  // Optional, will be called each time the track group's `playState` property has changed.
  onPlayStateChanged = playState => { console.log(playState); },
  // Optional, will be called each time the current `position` property has changed.
  onPositionChanged = position => { console.log(position); },
});

// Example for changing the volume to 50% in the second track:
player.tracks[1].gainParams = { ...track.gainParams, gain: 0.5 };

// Example for setting the second track as the solo track:
player.soloTrackIndex = 1;

// See the `Track` class for methods and properties

Concurrency

As downloading and decoding multiple media files can get pretty resource-intensive (and therefore can even lead to browser craches), there is some concurrency control built into this library that ensures that only a certain number of files can be processed (downloaded/decoded) at the same time. In order to changes these global settings, you can use the GlobalMediaQueue object:

// Only allow 5 parallel downloads (default: 2)
GlobalMediaQueue.maxDownloadConcurrency = 5;
// Only allow 5 parallel decoding processes (default: 2)
GlobalMediaQueue.maxDecodingConcurrency = 5;
// Only allow 5 media files to be processed (i.e. downloaded AND decoded)
// at the same time (default: 2)
GlobalMediaQueue.maxMediaSourceConcurrency = 5;

OER learning platform for music

Funded by 'Stiftung Innovation in der Hochschullehre'

A Project of the 'Hochschule für Musik und Theater München' (University for Music and Performing Arts)

Project owner: Hochschule für Musik und Theater München
Project management: Ulrich Kaiser