Playing Multiple Track
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 ?
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.
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 ?
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.
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;
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
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.
@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 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.
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 ?
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.
any update on this please , I have the same issue