souporserious / react-media-player

React audio and video player.
https://souporserious.github.io/react-media-player/
ISC License
470 stars 100 forks source link

add connectSource prop to Player #50

Closed souporserious closed 6 years ago

souporserious commented 6 years ago

Adds connectSource prop to help with connecting AudioNode[s] for easier audio manipulation.

Simple panning example:

class Panner {
  constructor({ source, audioContext }) {
    this._source = source
    this._audioContext = audioContext
  }

  connect() {
    this._splitter = this._audioContext.createChannelSplitter(2)
    this._gainLeft = this._audioContext.createGain()
    this._gainRight = this._audioContext.createGain()
    this._merger = this._audioContext.createChannelMerger(2)
    this._source.connect(
      this._splitter,
      0,
      0
    )
    this._splitter.connect(
      this._gainLeft,
      0
    )
    this._splitter.connect(
      this._gainRight,
      1
    )
    this._gainLeft.connect(
      this._merger,
      0,
      0
    )
    this._gainRight.connect(
      this._merger,
      0,
      1
    )
    return this._merger
  }

  setPosition(amount) {
    this._gainLeft.gain.value = amount <= 0 ? 1 : 1 - amount
    this._gainRight.gain.value = amount >= 0 ? 1 : 1 + amount
  }
}

class AudioPlayer extends Component {
  _handlePannerChange = ({ target }) => {
    const x = +target.value
    const y = 0
    const z = 1 - Math.abs(x)
    this.panner.setPosition(x, y, z)
  }

  _connectSource = (source, audioContext) => {
    this.panner = new Panner({ source, audioContext })
    return this.panner.connect()
  }

  render() {
    return (
      <Media>
        <div>
          <Player
            ref={c => (this._player = c)}
            src={`/audio/podcast.mp3`}
            connectSource={this._connectSource}
          />
          <input
            type="range"
            defaultValue="0"
            min="-1"
            max="1"
            step="any"
            onChange={this._handlePannerChange}
          />
        </div>
      </Media>
    )
  }
}