Current position / time display?
thespice opened this issue · comments
Love what you've done here!
Can't seem to find the methods for getting / displaying the current time and duration though.
In wavesurfer they are :
getCurrentTime()
getDuration()
Have you implemented either of these (with different names - tried these - they don't work) or something else that just isn't mentioned in the docs?
Kinda need time display and position tracking for any audio player.
Love what you've done here!
Thanks :)
Can't seem to find the methods for getting / displaying the current time and duration though
Currently there is no easy way to get this, no. You could always query the embedded audio element yourself to get this information, but I agree that it would be nice to have methods for easily getting the current time and duration of the currently playing track. It should not be hard to add this functionality actually, so will do it soon.
Thanks Michael that is brilliant news!
I'm using it in a Meteor project with React and have implemented my own alternative to your playlist method. Querying the embedded audio element would be a bit long winded in this situation so having access to the time, duration and position in the API would be super helpful!
This feature has been added in v1.1.0.
Hey Michael,
Thank you so much for adding these new features.
I'm having a little trouble getting the duration and currentTime to display though.
When I try to call :
wavePlayer.duration()
I get :
TypeError: wavePlayer.duration is not a function
Am I using it the wrong way?
P.S Everything else you added in this version 1.1.0 is working beautifully.
EDIT : Nevermind... Found it. I was calling it as a function when it isn't ;)
wavePlayer.duration
Is all you need for anybody else reading this.
Glad you figured it out. Yes, both duration
and currentTime
are implemented as getters.
One thing I've just noticed.
The duration always returns NaN when called directly after load.then.play().
I assume it takes a few moments to read the duration from the headers?
I've tried running the following but it doesn't seem to do anything :
wavePlayer.on('play', function () {
console.log(wavePlayer.duration);
});
Am I using 'on' incorrectly here?
Lastly, couple of other potential enhancements..
A wavePlayer.ready method which could be used to get the duration correctly in this instance.
And the ability to programatically provide wavePlayer with the duration on load. (I have all of this data available in JSON files so this would speed things up massively in my situation without having to wait for the audioApi to do it's thing).
P.S. I understand that the last one is a bit pointless as I could just render that info directly from my JSON file but it might be cool to have it available in the wavePlayer API too.
Am I using 'on' incorrectly here?
Could you try instead
wavePlayer.on('waveplayer:canplay', function () {
console.log(wavePlayer.duration);
});
This event is fired when audio can start playing and so the duration should be known at that point.
And the ability to programatically provide wavePlayer with the duration on load.
I'm not convinced this is something you'd want to do to be honest. The duration information is an immutable quantity (i.e. an inherent property of the file you load). I don't see a logical reason for why you'd want to define this yourself. Plus it could potentially also lead to confusion, as you could then set the duration of an audio file to any value really.
Thanks Michael, that does work when console logging but I can seem to be able to use it in any of my functions. Everything seems to fire before it has got the duration data.
For example, my loadTrack function :
loadTrack() {
let duration = "0:00";
axios
.get('peaks/mp3.json')
.then(({ data })=> {
wavePlayer.load('audio/mp3.mp3', data).then(() => wavePlayer.play());
wavePlayer.on('waveplayer:canplay', function () {
duration = wavePlayer.duration;
});
this.setState ({
playing: true,
buttonText: 'fa fa-pause',
duration: duration
});
})
.catch((err)=> {})
}
This results in 0:00 (the init value, it doesn't update).
And if I try to set the state inside the canplay
function I'm out of scope :
wavePlayer.on('waveplayer:canplay', function () {
duration = wavePlayer.duration;
this.setState ({
playing: true,
buttonText: 'fa fa-pause',
duration: duration
});
});
this is not defined
I've also tried using it in ComponentDidUpdate
as well, which works initially but then I get a Too many recursions
error.
The only way I can get it working is by using it inside the play controls. This updates the duration correctly but obviously only if the user hits the play / pause button, which isn't ideal.
Any ideas?
Yes, this is more of a JavaScript thingie than waveplayer.js related, but I can help you out I think ;)
First of all, this:
wavePlayer.on('waveplayer:canplay', function () {
duration = wavePlayer.duration;
});
this.setState ({
playing: true,
buttonText: 'fa fa-pause',
duration: duration
});
won't work, because execution of the callback happens when waveplayer:canplay
is fired and so the setState()
call, although appearing after it is executed first. This is just the wonderful asynchronous nature of JavaScript you have to get used to. Things that appear synchronously in your code don't always execute in that order. So yes, you should call setState()
in the body of the callback as you already attempted. Now if you want to reference this
in the callback you will get undefined
, because this
is not defined in the scope of the callback function. Two ways to solve this (whichever you find more elegant):
- Probably easiest; assign
this
to a variable outside the callback and then reference that value when you callsetState
:
const me = this;
wavePlayer.on('waveplayer:canplay', function () {
duration = wavePlayer.duration;
me.setState ({
playing: true,
buttonText: 'fa fa-pause',
duration: duration
});
});
- Use
bind()
to bind thethis
keyword inside the function to whatever argument you pass tobind()
(which also happens to bethis
in your case). Little bit confusing, but in short,this
in an ordinary JavaScript function does not refer tothis
outside that function.
const callback = function () {
duration = wavePlayer.duration;
this.setState ({ // Now you can use "this" again
playing: true,
buttonText: 'fa fa-pause',
duration: duration
});
};
wavePlayer.on('waveplayer:canplay', callback.bind(this));
That should do it I think.
Absolute legend! Thank you so much, works perfectly :)