react-native-sound icon indicating copy to clipboard operation
react-native-sound copied to clipboard

Inaccurate timing of short sounds

Open MartinGio opened this issue 4 years ago • 1 comments

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 :

  • Creating my own sequencer, a setInterval loop every 10ms that checks when sounds must be played
  • Loading the sounds before they are used, of course
  • Trying in Release mode, but it doesn't change anything

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 !

MartinGio avatar Oct 04 '21 22:10 MartinGio

Please help us! The same issue.

valentinev-celadon avatar Sep 28 '23 09:09 valentinev-celadon