React Native syncing sound with Animated

1.2k Views Asked by At

I'm making an app which has a metronome in it. I'm using react-native-sound and Animated. I need for the metronome sound to trigger with very high accuracy, and also be in sync with an animation. I'm not massively experienced, so I've used a hacky solution (triggering the samples with an Animated.listener), but it's extremely inefficient:

  <Button
icon={this.state.paused ? <Icon name="play" size={25} color='white'/> : <Icon name="pause" size={25} color='white'/>}
onPress={() => {
  if (this.state.paused)
    {this.setState({paused: false});
    this.animateTiming();
    let loopCount = 0;
    this.animatedValue.addListener(({value}) => {
      loopCount++;
      if(value==1) loopCount=0;

      // metronome playback
      if ([0,60,120,180].includes(loopCount)) playSound(audioList[0], 0);
  });


    }

Does anyone have any suggestions of how to handle it better? Thank you!

Update #2

this.animateTiming() looks like this:

animateTiming(){
this.animatedValue.setValue(START_POINT);
Animated.loop(
    Animated.timing(this.animatedValue, {
      toValue: STOP_POINT,
      easing: Easing.linear,
      duration: 4000, //these are milliseconds
      useNativeDriver: true
    })
).start(); 

}

The loop is 4000ms long, so at 60fps loopCount goes up to 240. Hence, [0,60,120,180] means "play the sound every second". The delay happens at the beginning of each loop, when the render function is called. I've identified that the source of the delay (about 80ms) is rendering musical notation using VexFlow (see the example in "Getting Started" in this link).

The question turns out to be, whether it's possible for the VexFlow rendering and the animation to run in parallel somehow (the audio needs to be perfectly in time, and a slight delay with rendering the notation is not a problem). Pre-rendering notation is not feasible, as what is displayed depends on the user's actions in the previous loop cycle.

1

There are 1 best solutions below

0
On

[...] so at 60fps loopCount goes up to 240. Hence, [0,60,120,180] means "play the sound every second"

This is an assumption that it will be 60 fps. Actual framerate will depend on capabilities of the device, and how much calculation is done each frame. It varies in time. Any fluctuation in FPS will result in sound being played at the wrong time.

I've identified that the source of the delay (about 80ms) is rendering musical notation [...]

It looks like you are experiencing a drop in fps.

Solution

Metronome should click in constant intervals, so the correct approach would be to calculate the time difference between frames and check if specified amount of time has passed; if so then play "click" sound.

These sources may come handy: