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

Playing Multiple Track

Open sabynamboo opened this issue 7 years ago • 11 comments

Hi All, I am facing one issue, I am trying to create one simple app with multiple tracks. So I have files like

Vocal.mp3, Drums.mp3, Claps, Guitar etc... So whenever we press the play button all these files should play without any delay. Is it possible or not ?

sabynamboo avatar Nov 15 '18 05:11 sabynamboo

Hi @sabynamboo

Yes, this sould be possible, as it is possible to play multiple sounds at the same time (the readme says: "You can play multiple sound files at the same time.") and also preload the sound effects so you can play them without any delay.

flogy avatar Nov 26 '18 12:11 flogy

But when I play some times the tracks are not syncing , like when I pause then I have to run the loop and pause it but when it play backs its not syncing. So do you have any idea how to do that ?

sabynamboo avatar Nov 26 '18 13:11 sabynamboo

Without knowing in detail how you have coded this I would just suggest to make sure all tracks are loaded (see Sound.prototype.isLoaded) and then just play them all together.

flogy avatar Nov 26 '18 13:11 flogy

Sorry I am new to this, here I am attaching the file. So this getTracksFromApi() will return all tracks like Drums.mp3 , Vocal.mp3, Guitar.mp3 etc . Please help me

import React, {Component} from 'react'; import {Button, Alert, Text, View, TouchableOpacity, TouchableHighlight, StyleSheet, Image, ImageBackground, FlatList} from 'react-native'; import Sound from 'react-native-sound'; import { EventRegister } from 'react-native-event-listeners' import bgImage from '../images/headset.png'; import TimerMixin from 'react-timer-mixin'; import * as constants from './Tracks';

export default class MusicPage extends Component {

constructor(props){
    super(props);
    Sound.setCategory('Playback', true);
    this.soundList = new Array();
    this.soundTwo = Sound;
    this.totalCount = 0;
    this.state = {
        loopingSound: undefined,
        tests: {},
        totalCount: 0,
        totalTime: 0,
        showPlay: false,
        isPaused: false,
        isLoading: true,
        isPlaying: false,
        isFinished: true,
        soundList: Array(),
        muteList: Array(),
        playListData: Array(),
        
      };

    this.playListData = [];
   
    
}
getTracksFromApi(){
  return fetch(constants.API_URL+"gettracks/songid/xddr32129",{
    method: 'GET',
    headers: {
      Accept: 'application/json',
      'Content-Type': 'application/json',
    }
  })
  .then((response) => response.json())
  .then((responseJson) => {
    var responseData = Array();
    for(var key in responseJson){
      responseData.push({
        id: key,
        title: responseJson[key].title,
        url: constants.MEDIA_URL+responseJson[key].filename,
        muted: false

      })
    }
    this.setState({
      isFinished: false,
      playListData: responseData
    })
    this.playMusic();
    return responseJson;
  })
  .catch((error) => {
    console.error(error);
  });
}
showPlayerCount(){
  console.log("Count", this.state.totalCount)
}
updateCount(){
  this.setState({ totalCount: this.state.totalCount + 1 });
  console.log("Playlist len", this.state.playListData.length)
  if(this.state.totalCount == this.state.playListData.length){

    setTimeout(function () {
      this.setState({
        showPlay: !this.state.showPlay

      })
    }.bind(this), 100);
    //this.playSong();

  }
}
resetCount(){
  this.setState({ totalCount: 0 });
}
resumeMusic(){
    this.setState({
        isPaused: !this.state.isPaused,
        isPlaying: !this.state.isPlaying
    });  
  for(var i=0; i<this.state.soundList.length; i++){
    console.log("Resumed", i)
    this.state.soundList[i].play();
  }
  console.log("I am here")


}
releaseSongs(){

}

playSong(){
  
  if(this.state.isPaused){
    this.resumeMusic();
    return;
  }
  for(var i=0; i<this.state.soundList.length; i++){
    if(this.state.soundList[i].isLoaded()){
      this.state.soundList[i].play((success) => {
        if(success){
          console.log('successfully finished playing');
          this.setState({
            // isFinished: true,
            // isPaused: false,
            isPlaying: false
          });
          // this.state.soundList[i].release();

        }else{
              console.log('playback failed due to audio decoding errors');

        }
      });
    }else{
      console.log("Found issues with track loading", this.state.soundList[i])
    }

  }
  this.togglePlay();
}
getMuteText(index){
  // Get mute text based on the active status
  if(this.isMuted(index)){
    return "Unmute";
  }else{
    return "Mute";
  }
}
setMute(index){
  //console.log("Index", index)
  var index = this.state.soundList.findIndex(x => x._filename==index);
 // console.log(this.state.soundList[index]);
  if(index != -1){
    // Check its already muted or not
    if(this.isMuted(index)){
      // its already muted so unmute
      console.log("Call unmute")
      this.state.soundList[index].setVolume(1); 
    }else{
      // Call mute
      console.log("Call mute")
      this.setMuteList(index);
      //console.log(this.state.muteList)
      this.state.soundList[index].setVolume(0); 
    }

  }

  // for(var i=0; i<this.state.soundList.length; i++){
  //   console.log(this.state.soundList[i]._filename)
  // }
}
isMuted(index){
  var index = this.state.muteList.findIndex(x => x.index==index);
  if(index == -1){
    return false
  }else{
    this.state.muteList.splice(index, 1);
    return true;
  }
    

}
setMuteList(index){
  this.state.muteList.push({
    index: index
  })

}
togglePlay(){
  this.setState({
    isPlaying: !this.state.isPlaying
  });
}
togglePause(){
  this.setState({
    isPaused: !this.state.isPaused
  });
}
toggleLoading(){
    this.setState({
        //isLoading: !this.state.isLoading,
        isPlaying: !this.state.isPlaying,
    });
}
componentWillMount(){
  this.getTracksFromApi();
  this.showPlayerCount();
  this.state.soundList = [];
  

}
componentWillUnmount(){
    console.log("Sound list", this.state.soundList.length)

}
componentWillReceiveProps(nextProps){
  console.log("nextProps", nextProps)
}
componentDidUpdate(prevProps, prevState){
  console.log("Called inner",prevProps, this.state.totalCount)

}

pauseMusic(){
    this.setState({
        isPaused: !this.state.isPaused,
        isPlaying: !this.state.isPlaying
    });  
  for(var i=0; i<this.state.soundList.length; i++){
    console.log("Paused", i)
    this.state.soundList[i].pause();
  }
  console.log("I am here")

}
showText(){
  return "Some text"
}
loadTracks(i){
  setTimeout(function () {

    console.log("URL", this.state.playListData[i].url)
    const sng = new Sound(this.state.playListData[i].url, null, (error) => {
      if (error) {
        console.log('failed to load the sound', error);
        return;
      }
      console.log("Song  loaded "+i)
      if(sng.isLoaded()){
        this.state.soundList.push(sng);
        this.updateCount();
        //console.log("Sound Duration", sng.getDuration())
      }
     // console.log("Sound list", this.soundList)
      // loaded successfully

    });

  }.bind(this), 1000);
}

playMusic(){
    this.setState({
        isLoading: !this.state.isLoading
    });  
    this.forceUpdate();
    this.resetCount();

      var i = 0
      for(i=0; i < this.state.playListData.length; i++){
    
            this.loadTracks(i);

        }

}

render(){
    return (
      <ImageBackground source={bgImage} style={styles.backgroundContainer}>
        <View style={styles.container}>


          <View style={styles.logoContainer}>
              <Image 
                style={styles.logo}
                source={require('../images/download.png')} />
                <Text >{this.state.showPlay} Play</Text>
          </View>
          <View>
            <FlatList
              data={this.state.playListData}
              renderItem={({item}) => 
              <View>
              <Button onPress={this.setMute.bind(this, item.url)} title="Mute" /> 
              
              <Text style={styles.item} key={item.id}>{item.title}</Text>
              </View>
              }
              keyExtractor={(item, index) => index.toString()}
            />


          </View>

          <View style={styles.playButtonContainer}>
         {this.state.showPlay && !this.state.isPlaying && <Button onPress={this.playSong.bind(this)} title="Play"></Button> }
              { this.state.isPlaying  && <Button title="Pause" onPress={this.pauseMusic.bind(this)}></Button> }
              
          </View>



          </View>
      </ImageBackground>




    );
}

} var styles = StyleSheet.create({ backgroundContainer: { flex:1, width: null, height: null, alignItems: 'center', backgroundColor: '#000000',

}, container: { flex: 1, alignItems: 'center', alignItems: 'center', }, overlay: { opacity: 0.5, }, logo: { top: 20, width: 195, height: 40, }, backdrop: { flex:1, flexDirection: 'column' }, playButtonContainer: { flexGrow: 1, position: 'absolute', justifyContent: 'flex-end', marginBottom: 36, bottom: 2

}, item: { padding: 10, fontSize: 18, height: 44, flex: 1, backgroundColor: '#ecf0f1', opacity: 0.5, top: 80

}, }); const styles1 = StyleSheet.create({ container : { flex : 1, backgroundColor: '#000000', alignItems: 'center', }, overlay: { opacity: 0.5, backgroundColor: '#000000' }, logoContainer: { alignItems: 'center', flexGrow: 1, justifyContent: 'center', position: 'absolute', top: 0, bottom: 0, left: 0, right: 0,

}, logo: { width: 195, height: 40,

} })

// export default loginPage;

sabynamboo avatar Nov 26 '18 15:11 sabynamboo

Issue I have now is , I have to keep a counter for tracking the number of tracks, like if I have 7 tracks then the play button should only show once all loaded. Now on clicking of Play button I have to play all together. And on clicking on Pause I have to Pause all tracks, then I have to play all music when it resume

sabynamboo avatar Nov 26 '18 15:11 sabynamboo

I am also new to this library and just assumed this would work. Reading your code I'd say this should be fine as you are loading the sound effects before you put them into the this.state.soundList array. When playing you only play the loaded sounds which is what I meant in my comment before. The only possibility I see is that not all sounds are in the array yet, so only some of the sounds will play. But they should be synced in my opinion... Maybe this is still a problem of the library or a simple performance issue?

By the way, please check this guide about code formatting as it will help you to make your code comment more readable.

flogy avatar Nov 27 '18 10:11 flogy

@sabynamboo I was also facing the same issue. Then I have cached the urls in locally with rn-fetch-blob plugin without downloading files it's not possible to smooth play pause. I have faced it before. I am now facing after doing this that. Play button doing a for loop and play() method for all songs suppose 3 songs. And pause() method has a another loop for 3 songs. The issue arrises in delaying few seconds after pause and play after 10 seconds. My code is similar to @sabynamboo code. I am also using for loop on play and pause. Can anybody suggest. It's obvious that multiple time play pause may cause 1-3 seconds delay on playing and pausing the song instance.

My application is like multiple songs playing at once (ex- vocals.mp3, drum.mp3, clap.mp3)

prashen avatar Oct 09 '19 12:10 prashen

@prashen Loops do hit the performance a lot, do try and see if you can work out an alternative for that. Also even files written to the local bundle has sync issues - and this happens after I load the files beforehand to reduce the delay. Might be a bug in the MediaPlayer.

ARKEOLOGIST avatar Dec 24 '19 15:12 ARKEOLOGIST

was this solved ? Im trying to do the same thing I have 8 audios files and they should be played at the same time ,it seems like it works only for 4 audio files which plays perfect at the same time but with more there some delay . I´m loading all audios before playing and it doesnt work (delay is more remarkable in ios than in android) Any suggestion ?

JosePatricio avatar Sep 21 '21 02:09 JosePatricio

Same issue here. As @JosePatricio said I can load a few sounds and play at same time with no issue, the tracks are in sync. But I noticed that if I pause and play them all at once they go out of sync (tested with 2 sounds). Even tried to set position of sound 2 to that of sound 1 with

soundOne.getCurrentTime((seconds) => {
  soundTwo.setCurrentTime(seconds);
});

on play or pause but not working.

daniel-carvajal avatar Nov 03 '21 17:11 daniel-carvajal

any update on this please , I have the same issue

Oussamaab1998 avatar Oct 02 '23 13:10 Oussamaab1998