GithubHelp home page GithubHelp logo

doc22940 / redux-sounds Goto Github PK

View Code? Open in Web Editor NEW

This project forked from joshwcomeau/redux-sounds

0.0 1.0 0.0 1.61 MB

Middleware for playing audio / sound effects using Howler.js

License: MIT License

JavaScript 100.00%

redux-sounds's Introduction

Redux Sounds

build status npm version Coverage Status

Redux middleware that lets you easily trigger sound effects on actions. Makes it completely trivial to do so, by adding a meta property to any action:

export function danceMoves() {
  return {
    type: 'DANCE_MOVES',
    meta: {
      sound: {
        play: 'groovyMusic'
      }
    }
  }
};

Uses Howler.js under the hood, which uses Web Audio API when available, with a graceful fallback to HTML5 Audio.

Installation

Preferred: NPM

npm i -S redux-sounds

Also available: UMD

UMD builds are also available, for single-file usage or quick hacking in a JSbin. Simply add dist/redux-sounds.js or dist/redux-sounds.min.js to your file in a <script> tag. The middleware will be available under ReduxSounds.

Setup

soundsMiddleware works similarly to other Redux middleware, with one important exception: it needs to be pre-loaded with sound data.

Here's an example setup:

/* configure-store.js */

import { createStore, combineReducers, applyMiddleware } from 'redux';
import soundsMiddleware from 'redux-sounds';

import { gameReducer } from '../reducers/game-reducer';

// Our soundsData is an object. The keys are the names of our sounds.
const soundsData = {
  // If no additional configuration is necessary, we can just pass a string  as the path to our file.
  endTurn: 'https://s3.amazonaws.com/bucketName/end_turn.mp3',

  // Alternatively, we can pass a configuration object.
  // All valid howler.js options can be used here.
  winGame: {
    src: [
      'https://s3.amazonaws.com/bucketName/win_game.mp3',
      'https://s3.amazonaws.com/bucketName/win_game.wav'
    ],
    volume: 0.75
  },

  // Audio sprites are supported. They follow the Howler.js spec.
  // Each sprite has an array with two numbers:
  //   - the start time of the sound, in milliseconds
  //   - the duration of the sound, in milliseconds
  jumps: {
    src: [ 'https://s3.amazonaws.com/bucketName/jumps.mp3' ],
    sprite: {
      lowJump: [0, 1000],
      longJump: [1000, 2500],
      antiGravityJump: [3500, 10000]
    }
  }
}

// Pre-load our middleware with our sounds data.
const loadedSoundsMiddleware = soundsMiddleware(soundsData);

// Use as you would any other middleware.
const store = createStore(gameReducer, applyMiddleware(loadedSoundsMiddleware));
// (Using the condensed createStore released in Redux v3.1.0)

Howler has much more advanced capabilities, including specifying callbacks to run when the sound has completed (or failed to complete), looping sounds, fading in/out, and much more. See their documentation for the complete list.

Usage

Once your store is created, dispatching actions that trigger sounds is simple.

Using the convention established in the rafScheduler Middleware example, a new meta property can be attached to actions. This meta property should have a sound key, and its value should be that of a registered sound.

Continuing from our example above, we have 5 possible sounds: endTurn, winGame, and 3 flavors of jumps.

The Howler methods other than play follow almost the same API as Howler:

Howler

sound.fade(1, 0, 1000, id);
sound.stop(id);

redux-sounds action

// fade
meta: {
  sound: {
    fade: ['endTurn', 1, 0, 1000]
  }
}

// stop
meta: {
  sound: {
    stop: 'endTurn'
  }
}

For sprites, separate the sound name from the sprite name with a period (.). A couple examples of the actions we can dispatch:

/* game-actions.js */

export function endTurn() {
  return {
    type: 'END_TURN',
    meta: {
      sound: {
        play :'endTurn'
      }
    }
  }
}

export function lowJump() {
  return {
    type: 'LOW_JUMP',
    meta: {
      sound: {
        play: 'jumps.lowJump'
      }
    }
  }
}

export function lowJumpStop() {
  return {
    type: 'LOW_JUMP_STOP',
    meta: {
      sound: {
        stop: 'jumps.lowJump'
      }
    }
  }
}

export function lowJumpFade() {
  return {
    type: 'LOW_JUMP_STOP',
    meta: {
      sound: {
        fade: ['jumps.lowJump', 0 , 1, 2]
      }
    }
  }
}

Note: It is worth noting that it is unlikely that you'll need to create new actions for your sound effects; You'll probably want to just add meta properties to pre-existing actions, so that they play a sound in addition to whatever else they do (change the reducer state, trigger other middleware, etc).
Also Note: When a sound is playing multiple times at once, Howler methods (stop, fade, pause, etc.) will apply to all playing instances

Troubleshooting

Unregistered sound

When you dispatch an action with a meta.sound property, redux-sounds looks for a registered sound under that name. If it cannot find one, you'll get a console warning:

The sound 'foo' was requested, but redux-sounds doesn't have anything registered under that name.

To understand why this is happening, let's examine the link between registering a sound when the store is created, and triggering a sound when an action is dispatched.

When you create your store, you pass in an object like so:

const soundsData = {
  foo: 'path/to/foo.mp3'
};

The keys in that object must correspond to the value specified when you dispatch your action:

dispatch({
  type: 'ACTION_NAME',
  meta: { sound: { play: 'foo' }
});

Make sure these two values are the same!

Invalid sprite

When your meta.sound value has a period in it (eg. foo.bar), redux-sounds breaks it apart so that the first half is the sound name, and the second half is the sprite name.

If redux-sounds has a sound registered under 'foo', but that sound has no specified sprite for 'bar', you get a console warning that resembles:

The sound 'foo' was found, but it does not have a sprite specified for 'bar'.

It is possible that there is a typo, either in the meta.sound property or the sprite data passed in on initialization.

A missingSoundData error throws when I try loading the page.

Unlike other middleware, you cannot simply pass it to Redux as-is:

import soundsMiddleware from 'redux-sounds';

// DON'T do this:
const store = createStore(rootReducer, applyMiddleware(soundsMiddleware));

The reason for this is that before the store can be registered, you need to pass it data about which sounds it needs to handle.

You must first invoke soundsMiddleware with a soundsData object:

import soundsMiddleware from 'redux-sounds';
import { soundsData } from '../data/sounds';

// Important step:
const loadedSoundsMiddleware = soundsMiddleware(soundsData);

const store = createStore(rootReducer, applyMiddleware(loadedSoundsMiddleware));

Tests

To run: npm run test

Using Mocha for test-running, Chai Expect for assertions, and Istanbul for test coverage.

While test coverage is 100%, because the tests run in Node, and Node has no ability to play sounds, the actual output is not tested.

Because I've delegated these duties to Howler, though, I don't feel too bad about that. I check to make sure the right info is passed to Howler at the right time; Howler's tests can take it from there.

Planned functionality

Got ideas for must-have functionality? Create an issue and let's discuss =)

Contributions

Contributors welcome! Please discuss additional features with me before implementing them, and please supply tests along with any bug fixes.

License

MIT

redux-sounds's People

Contributors

joshwcomeau avatar gekorm avatar dependabot[bot] avatar larrybotha avatar

Watchers

 avatar

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.