Skip to content

Latest commit

 

History

History
103 lines (71 loc) · 3.47 KB

README.md

File metadata and controls

103 lines (71 loc) · 3.47 KB

Human Record Player

Leer en español

This repo demonstrates the basic controls for https://humanrecordplayer.com.

RPReplay_Final1655745366.MP4

Development

Safari requires https to request device motion/orientation events.

  1. Get a server running in the root directory (e.g., python3 -m http.server --cgi 8000)
  2. Use ngrok to explose the local server (e.g., ngrok http 8000)
  3. Point your mobile browser at the ngrok-generated URL

Audio assets

For full mobile browser support you'll want to provide both .mp3 and .ogg. To get any audio from the internet...

  1. Use youtube-dl to download a YouTube video.
  2. Use ffmpeg to isolate the audio
  3. Use ffmpeg to convert audio to .mp3 and .ogg
  4. Spin
youtube-dl <URL> -o video
ffmpeg -i video.mkv -vn -acodec copy audio.aac
ffmpeg -i audio.aac audio.mp3
ffmpeg -i audio.aac audio.ogg

Caveats

  • Safari desktop does not support DeviceMotion events
  • Chrome desktop does support DeviceMotion events. Chrome desktop can be used to debug with a constant playback rate.

Credits

Shoutout to @feross for https://github.com/feross/unmute-ios-audio, and @searls for the iOS 14.5+ patch

Code Samples

In this section, we showcase some specific code snippets from the project to give you a taste of how it works.

Initialization of the Motion Class

Here's how the Motion class is initialized in js/script.js:

const motion = new Motion(window, {
  update(val) {
    const absVal = Math.abs(val)

    let rate = 1.0
    if (absVal > groove.min && absVal < groove.max) {
      rate = 1.0
    } else if (absVal < groove.min) {
      rate = map(absVal, 0, groove.min, 0, 0.99)
    } else {
      rate = map(absVal, groove.max, 250, 1.01, 2.0)
    }

    audioPlayer.updatePlaybackRate(rate, val < 0)

    // Update debug UI
    const rpm = degToRpm(absVal).toFixed(0)
    playbackRateOutput.textContent = rate.toFixed(2)
    rotationRateOutput.textContent = `${val.toFixed(0)} deg/s (${rpm} RPM)`
  }
})

Why do programmers prefer dark mode? Because light attracts bugs!

The onMotionUpdate Method

And here's the onMotionUpdate method from js/motion.js:

onMotionUpdate(e) {
  let now = new Date()

  if ((now - this.lastReadAt) > Motion.MotionReadInterval) {
    this.lastReadAt = now

    const { beta, gamma } = e.rotationRate
    const isHorizontal = this.deviceOrientation === Motion.DeviceOrientation.Horizontal
    let value = (isHorizontal ? gamma : beta) * -1

    this.addValue(value)

    const sum = this.values.reduce((a, b) => { return a + b }, 0)
    const avg = sum / this.values.length // smoothed

    if (this.onMotionUpdateHandler) {
      this.onMotionUpdateHandler(avg)
    }
  }
}

Why was the JavaScript developer sad? Because he didn't know how to un-null his feelings.