2

我正在制作一个带有节拍器的应用程序。我正在使用 react-native-sound 和 Animated。我需要节拍器的声音以非常高的精度触发,并且与动画同步。我没有大量经验,所以我使用了一个 hacky 解决方案(使用 Animated.listener 触发样本),但效率极低:

  <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);
  });


    }

有人对如何更好地处理它有任何建议吗?谢谢!

更新#2

this.animateTiming() 看起来像这样:

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(); 

}

循环长度为 4000 毫秒,因此在 60fps 时 loopCount 上升到 240。因此,[0,60,120,180] 表示“每秒播放声音”。延迟发生在每个循环的开始,即调用渲染函数时。我已经确定延迟的来源(大约 80 毫秒)是使用 VexFlow 渲染乐谱(请参阅此链接中“入门”中的示例)。

问题是,VexFlow 渲染和动画是否有可能以某种方式并行运行(音频需要完全及时,渲染符号的轻微延迟不是问题)。预渲染符号是不可行的,因为显示的内容取决于用户在前一个循环周期中的操作。

4

1 回答 1

0

[...] 所以在 60fps loopCount 上升到 240。因此,[0,60,120,180] 表示“每秒播放声音”

这是一个假设,它将是 60 fps。实际帧率将取决于设备的功能,以及每帧进行多少计算。它随时间变化。FPS 的任何波动都会导致声音在错误的时间播放。

我已经确定延迟的来源(大约 80 毫秒)是渲染乐谱 [...]

看起来您的 fps 有所下降。

解决方案

节拍器应该以恒定的间隔单击,因此正确的方法是计算帧之间的时间差并检查是否经过了指定的时间量;如果是这样,则播放“点击”声音。

这些来源可能会派上用场:

于 2020-12-18T14:03:00.307 回答