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

@notross/react-waveform

v0.0.14

Published

A React component for rendering audio waveforms, with support for multiple audio sources and custom styling.

Downloads

11

Readme

Installation

npm | yarn --------------------------------- | ------------------------------------ | npm i @notross/react-waveform | yarn add @notross/react-waveform

Types

AudioTrack

interface AudioTrack {
  id: number | string
  src: string
}

ConfigOptions

type ConfigColors = {
  default: string
  active: string
  past: string
}

interface ConfigOptions {
  colors: ConfigColors
  radius: string
  activeHeight: string
  gap: string
}

Components

WaveformProvider

import React from 'react'
import { WaveformProvider } from '@notross/react-waveform'

export default function App({ children }: {
  children: React.ReactNode,
}) {
  return (
    <WaveformProvider>
      {children}
    </WaveformProvider>
  )
}

WaveformProvider takes an optional argument of options: ConfigOptions. These options will apply to every <Waveform /> component that does not have its own ConfigOptions set.

import React from 'react'
import { WaveformProvider, ConfigOptions } from '@notross/react-waveform'

const options: ConfigOptions = {
  colors: {
    active: 'rgba(255, 0, 0, 1)',
    default: 'rgba(255, 0, 0, 0.75)',
    past: 'rgba(255, 0, 0, 0.5)',
  },
  activeHeight: '0.375rem',
  gap: '2px',
  radius: '4px',
}

export default function App(props: React.ComponentProps) {
  return (
    <WaveformProvider options={options}>
      {props.children}
    </WaveformProvider>
  )
}

Waveform

// audio-player.tsx
import { AudioTrack, Waveform } from '@notross/react-waveform'

export function AudioPlayer({ track }: {
  track: AudioTrack
}) {
  return (
    <Waveform track={track} />
  )
}

<Waveform /> can take three arguments:

  • track: AudioTrack
  • columns: number (optional)
  • options: ConfigOptions (optional)

argument | description | type --- | --- | --- track | An object containing the id and src of the track | AudioTrack columns | Specifies the number of segments in the rendered audio wave. Default value is 60 | number options | Optional styling specifications. These options will override any default options or options set in the WaveformProvider | ConfigOptions

// custom-audio-player.tsx
import { AudioTrack, ConfigOptions, Waveform } from '@notross/react-waveform'

export function AudioPlayer({ track, activeColor, gap }: {
  activeColor: string,
  gap: string,
  track: AudioTrack
}) {
  const options: Partial<ConfigOptions> = {
    colors: {
      active: activeColor,
    },
    gap: gap,
  }

  return (
    <Waveform track={track} options={options} />
  )
}

Hooks

useWaveform

The useWaveform hook exposes the following variables and functions: name | description | type | arguments ----- | ----------- | ---- | --------- armTrack | Plays an audio track from the tracks array | Function | id: number \| string current | The currently armed track | Object: AudioTrack | loading | Status of track array population | boolean | loadTracks | Populates the tracks array with a list of audio sources, either replacing the array's contents or appending the passed items to the current array | Function | tracks: AudioTrack[], reset: boolean metadata | Data about the currently armed track, such as track duration, time elapsed (while playing) | Object: Metadata | tracks | Array of tracks that have been loaded | Object: AudioTrack[]

loadTracks

The loadTracks function takes the following arguments:

  • tracks: AudioTrack[]
  • reset: boolean

argument | description | type --- | --- | --- tracks | Takes an array of objects specifying the audio tracks to be loaded and rendered as waveforms | AudioTrack[] reset | Indicates whether the passed tracks will replace or be appended to the existing array. Default value is false | boolean

tracks (argument)

Each track in the tracks array is of type AudioTrack, which includes two properties:

  • id: string | number
  • src: string

key | description | type --- | --- | --- id | The id must be unique, as it is used to synchronize waveforms throughout the application (e.g. if a track's waveform is playing in a list of tracks and is being displayed simultaneously in a separate component) | string or number src | The src specifies the location of the audio file. | string

import { useEffect } from 'react'
import { useWaveform, AudioTrack, Waveform } from '@notross/react-waveform'

// Audio track URLs
const TRACK_LIST = [
  'https://demo3.bigfishaudio.net/demo/free11_1.mp3',
  'https://s3-us-west-2.amazonaws.com/s.cdpn.io/254249/break.ogg',
  'https://free-loops.com/data/mp3/d0/b8/bc44c037a3dfdb90838c13513e58.mp3',
  'https://free-loops.com/data/mp3/68/c0/af53529e97d928a43d8dd7272ae3.mp3',
]

// URLs mapped to an AudioTrack array
const TRACKS = TRACK_LIST.map((url, index: number) => ({
  id: index,
  src: url,
}))

export function Tracks() {
  const { loadTracks } = useWaveform()

  useEffect(() => {
    loadTracks(TRACKS) // Load the tracks into the Waveform state
  }, [loadTracks])
}

armTrack

armTrack plays the specified track through an <audio> element in <WaveformProvider>. Once a track is armed, any <Waveform /> whose track id matches the armTrack id will render the audio waveform.

The armTrack function takes only one argument:

  • id: string | number

argument | description | type --- | --- | --- id | The id comes from the tracks array, specifying a loaded track for playback and visualization | string or number

// play-button.tsx
import { useWaveform } from '@notross/react-waveform'

export function PlayButton({ id }: { id: string }) {
  const { armTrack } = useWaveform()

  return (
    <button onClick={() => armTrack(id)}>{'▶️'}</button>
  )
}

current

current is the currently armed/playing track. If no track is armed, current will evaluate to null.

import { useWaveform } from '@notross/react-waveform'
import { AudioPlayer } from './audio-player.tsx'

export function AudioPlayer() {
  const { current } useWaveform()

  return (
    <>

      {/* current is not null */}
      {current && (
        <div>
          <AudioPlayer track={current} />
          <p>{`Currently playing track #${current.id}`}</p>
        </div>
      )}

      {/* current is null */}
      {!current && <p>No tracks are playing at this time.</p>}
    </>
  )
}

tracks

tracks is an array of all loaded tracks. tracks are of type AudioTrack.

import { useWaveform } from '@notross/react-waveform'
import { AudioPlayer } from './audio-player'
import { PlayButton } from './play-button'

export function TrackList() {
  const { tracks } useWaveform()

  return (
    <ul>
      {tracks.map((track) => (
        <li key={track.id}>
          <PlayButton id={track.id} />
          <span>{`Track ID #${track.id}`}</span>
          <AudioPlayer track={track} />
        </li>
      ))}
    </li>
  )
}

metadata

metadata returns an object (type Metadata) containing information about the currently armed track, including track duration and playthrough progress (milliseconds/seconds/minutes). metadata includes four properties:

key | description | type --- | --- | --- duration | The length of the track in seconds (decimal) | number minutes | The number of minutes elapsed since playback started | number seconds | The number of seconds elapsed since playback started | number ms | The number of milliseconds elapsed since playback started | number

WaveformProvider (React Context API )

The WaveformProvider maintains the state for all loaded audio tracks, as well as play state.

Usage

First, import the WaveformProvider to the root of your application:

import { WaveformProvider } from '@notross/react-waveform';

Next, wrap the provider around the your root component, so that all child components will have access to the WaveformProvider state:

root.render(
  <WaveformProvider>
    <App />
  </WaveformProvider>
);

Any child component of WaveformProvider can utilize the useWaveform hook and the <Waveform /> component.

Finally, load tracks, arm tracks, and render waveforms using the useWaveform hook and the <Waveform /> component:

// audio-tracks.json

[
  {
    "id": "1",
    "src": "https://demo3.bigfishaudio.net/demo/free11_1.mp3"
  },
  {
    "id": "1",
    "src": "https://s3-us-west-2.amazonaws.com/s.cdpn.io/254249/break.ogg"
  },
  {
    "id": "1",
    "src": "https://free-loops.com/data/mp3/d0/b8/bc44c037a3dfdb90838c13513e58.mp3"
  },
  {
    "id": "1",
    "src": "https://free-loops.com/data/mp3/68/c0/af53529e97d928a43d8dd7272ae3.mp3"
  }
]
import { useEffect } from 'react';
import { useWaveform, AudioTrack, Waveform } from '@notross/react-waveform';

// import audio tracks
import audioTracks from './audio-tracks.json'

function TrackLibrary() {
  const { armTrack, current, loadTracks, tracks } = useWaveform();

  // load the tracks into the WaveformProvider context
  useEffect(() => {
    loadTracks(audioTracks as AudioTrack[])
  }, [loadTracks])

  return (
    <>
      <main>
        <ul>
          {/* List each track with a "play" button and its respective Waveform */}
          {tracks.map((track) => (
            <li key={track.id}>
              <button onClick={() => armTrack(track.id)}>{'▶️'}</button>
              <Waveform track={track} />
            </li>
          ))}
        </ul>
      </main>
      <footer>
        {/* Render the footer Waveform if a track is currently armed */}
        {current && (
          <Waveform
            track={current}
            columns={120}
            options={{
              colors: {
                default: '#ffffff',
              },
              gap: '1px',
              radius: '8px',
            }}
          />
        )}
      </footer>
    </>
  );
}