zmxv / react-native-sound

React Native module for playing sound clips
MIT License
2.78k stars 748 forks source link

Inaccurate timing of short sounds #756

Open MartinGio opened 2 years ago

MartinGio commented 2 years ago

Hi everyone !

I'm using react-native-sound in my app, and I would like to trigger drums sounds at the appropriate time to make a drum beat, each sound lasting 167 ms.

I'm experiencing delays that make the beat really unsteady, even if I did many things trying to optimise this :

When I trigger my AudioSequencer.start() function, JS Thread goes from 60fps to 30fps. The .play() function of the sound seems to be triggered at an appropriate moment, but is delayed for some reason I don't know.

I've noticed that with MP3 files it seems worse than WAV files. I tried of real devices, Samsung S10 and iPhone 6 : same results.

Also, for 1000ms and longer audio files, it works much better !

Here are some snippets of my code, if that helps.


let clic = new Sound(require('../audio/percus/simples/clic90.mp3'), null, (error)=>{})
let off = new Sound(require('../audio/percus/simples/_16ths_silence_90.wav'), null, (error)=>{})
let on = new Sound(require('../audio/percus/simples/16ths_90.wav'), null, (error)=>{})
var s1 = new Sound(require('../audio/notes/short_notes/us_E3.mp3'), null, (error)=>{})
var s2 = new Sound(require('../audio/notes/short_notes/us_F3.mp3'), null, (error)=>{})
var s3 = new Sound(require('../audio/notes/short_notes/us_Gb3.mp3'), null, (error)=>{})
var s4 = new Sound(require('../audio/notes/short_notes/us_G3.mp3'), null, (error)=>{})

let timestamps = [  100, 667, 667,   167, 167,167,167,167,167,167,167]
let rythms = [ clic, clic,  s1, s2, s3, null,   s1, s2, s3, s1  ]

const AudioSequencer = {
    rate: 10,
    setIntervalRef: null,
    dateReference : null,
    pausePosition: 0,
    i: 0,

    start: function(timestampsArray, soundsArray){
        clearInterval(this.setIntervalRef)
        this.i = 0
        let cumulTimestampsArray = cumulativeIntSumArray(timestampsArray)
        if(this.pausePosition !== 0) this.i = cumulTimestampsArray.findIndex((e)=> e > this.pausePosition) - 1
        this.dateReference = Date.now() - this.pausePosition;
        this.pausePosition = 0;
        this.setIntervalRef = setInterval(()=>{
            if((Date.now() - this.dateReference) > cumulTimestampsArray[this.i]){
                if(soundsArray[this.i] !== null){
                    soundsArray[this.i].stop()
                    soundsArray[this.i].play((success)=>{if(!success)console.log('woops !')})
                    }
                if(this.i === soundsArray.length - 1) clearInterval(this.setIntervalRef)
                this.i ++
            }
        }, this.rate)
    },
    pause: function(){
        this.pausePosition = Date.now() - this.dateReference
        clearInterval(this.setIntervalRef)
    },
    stop: function(){
        clearInterval(this.setIntervalRef)
    },

// In the render function

<Button title={"Start sequencer"} onPress ={()=>AudioSequencer.start(timestamps, rythms)}/>

If you have any suggestion that would be of great help !

valentinev-celadon commented 9 months ago

Please help us! The same issue.