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.