Change playback speed in exoplayer - exoplayer2.x

I am trying to add a button from which I can slow down the playback speed. The code looks like this:
fun setupButtons(view: View){
buttonContainer = view.findViewById(R.id.button_container)
slowPlayButton = view.findViewById(R.id.slow_button)
slowPlayButton.setOnClickListener({
if (!isSlowPlaying) {
player.setPlaybackSpeed(0.03f)
} else {
player.setPlaybackSpeed(1.0f)
}
isSlowPlaying = !isSlowPlaying
})
}
I have verified with debugger that player.setPlaybackSpeed(0.03f) is called, but the speed of the video is not changed.
If I instead set the playback speed when I set up the player, it is playing slowly.
private fun createAndShowVideo(baseFile: String) {
val videoFile = baseFile + ".mp4"
val mediaItem: MediaItem = MediaItem.fromUri(videoFile.toUri())
player.setMediaItem(mediaItem);
player.prepare();
player.addListener(this)
player.setPlaybackSpeed(0.03f)
}
What do I need to do to make the button call take effect?

The easiest solution seems to be to override the arrayexo_playback_speeds in an xml called arrays.xml:
<resources>
<string-array translatable="false" name="exo_playback_speeds">
<item>0.025x</item>
<item>0.1x</item>
<item>0.2x</item>
<item>0.4x</item>
<item>0.8x</item>
<item>#string/exo_controls_playback_speed_normal</item>
<item>1.25x</item>
<item>1.5x</item>
<item>2x</item>
</string-array>
</resources>

Related

Web audio playback contains clicks

I am trying to build a midi player using web audio API. I used tonejs to parse midi file into JSON. I am using mp3 files to play notes. Following are the relevant parts of the code:
//create audio samples
static async setupSample(audioContext, filepath) {
const response = await fetch(filepath);
const arrayBuffer = await response.arrayBuffer();
const audioBuffer = await audioContext.decodeAudioData(arrayBuffer);
return audioBuffer;
}
//play a single sample
static playSample(audioContext, audioBuffer, time) {
const sampleSource = new AudioBufferSourceNode(audioContext, {
buffer: audioBuffer,
playbackRate: 1,
});
sampleSource.connect(audioContext.destination);
sampleSource.start(time);
return sampleSource;
}
Scheduling samples:
async start() {
this.startTime = this.audioCtx.currentTime;
this.play();
}
play() {
let nextNote = this.notes[this.noteIndex];
//schedule samples
while ((nextNote.time + this.startTime) - this.audioCtx.currentTime <= 0.250) {
let s = Audio.playSample(this.audioCtx, this.samples[nextNote.midi], this.startTime + nextNote.time);
s.stop(this.startTime + nextNote.time + nextNote.duration);
this.noteIndex++;
if (this.noteIndex == this.notes.length) {
break;
}
nextNote = this.notes[this.noteIndex];
}
if (this.noteIndex == this.notes.length) {
return;
}
requestAnimationFrame(() => {
this.play();
});
}
I am testing code with a midi file which contains C major scale. I have tested the midi file using timidity and it is fine.
The code does play the midi file correctly execpet a small problem: I hear some clicking sounds during playback. The clicking increases with increasing tempo but does not completely go away even with tempo as small as 50bpm. Any ideas what could be going wrong?
Full code can be viewed at : https://test.meedee.in/
Nothing is "wrong". You are observing a phenomenon intrinsic to the physics of audio.
Chopping audio samples arbitrarily like this creates clicks at the transitions. Any instantaneous change in level is heard as a click. To get rid of the clicks, apply an envelope to the sample, blend adjacent notes, or apply a low-pass filter.

Stop SKAudioNode from Playing

I am trying to play footstep sounds only when the player is moving. I added a check to see if the player is already moving to make sure it would not play audio on top of each other.
For some reason footstepSound.run(SKAction.stop()) is not working which is causing a bunch of tracks to play over each other which sounds very bad.
Any ideas?
let footstepSound = SKAudioNode(fileNamed: "Footsteps.mp3")
if (degree != 50) {
if (isFootstepping) { return }
isFootstepping = true
self.addChild(footstepSound)
}
else if (isFootstepping && degree == 50) {
isFootstepping = false
footstepSound.run(SKAction.stop())
footstepSound.removeFromParent()
}
Solved! The issue is that the footstepSound variable was not globally declared. This was causing a new variable to be created on each function call, therefore when .removeFromParent was called it was never referencing the old variable.

Flutter Audioplayers delay

I'm coding a small game with the Flutter Framework.
I'm using audioplayers for the Sounds.
It works fine like this, when calling it for example 2 times a second.
But whenn I call it more than 5 times and again in the next second at some point the sound has like a delay and then after a second or so all the sounds play at once :) That sounds weired.
I also tested the audioplayers example from github on my iphone. Repeating the sounds in low frequency is ok, but when I repeat clicking the button as fast as possible at some point it gets some delay and the same thing is happening.
Is there some way to stop the previous Sound before and then playing the next one or isnt this possible?
Or is there some other Idea how to deal with the sounds?
This is how I use it:
AudioCache upgradeSound = new AudioCache();
void playUpgradeSound() {
_playUpgradeSound(upgradeSound);
}
void _playUpgradeSound(AudioCache ac) async{
await ac.play('audio/upgr.mp3');
}
Thank you very much in advance
I solve similar problem by having singleton class, and after first play I can get the state, and I can stop previous play.
class Audio {
static final playerCache = AudioCache();
static AudioPlayer audioPlayer;
static void play(String audioName) async {
audioPlayer = await playerCache.play('$audioName.mp3');
}
static void stop() {
audioPlayer.stop();
}
}
...
child: IconButton(
onPressed: () {
try {
if (Audio.audioPlayer.state ==
AudioPlayerState.PLAYING) {
Audio.stop();
} else {
Audio.play('bid');
}
} catch (e) {
Audio.play('bid');
}
},
...
There is a line of code in its own documentation.
To use the low latency API, better for gaming sounds, use:
AudioPlayer audioPlayer = AudioPlayer(mode: PlayerMode.LOW_LATENCY);
In this mode the backend won't fire any duration or position updates. Also, it is not possible to use the seek method to set the audio a specific position. This mode is also not available on web.
I hope it is useful.

Unity: LoadScene does not work when fired from timer

in my game, when the player dies, a dying sound is played and once the sound is over, the scene is supposed to be reloaded when the user still has enough lives.
Before I had the sound, the play died instantly upon calling the death() function:
public static void Death()
{
AddCoinScript.coinCounter = 0;
LivesScript.livesCounter--;
if (LivesScript.livesCounter > -1)//to get 0 live
{
Debug.Log("TIMER");
var currentScene = SceneManager.GetActiveScene();
SceneManager.LoadScene(currentScene.name);
}
else
{
//TO DO GameOver
}
}
This worked like a charm.
But now I added a death sound to it. Unfortunately, unity doesnt provide an event handler for when the sound is done playing (I want the scene to be reloaded not instantly anymore, but after the death sound is done playing), so I have decided to take it upon myself to just build a timer. The timer fires right after the death sound is over. This is what this function has become:
public static void Death()
{
AddCoinScript.coinCounter = 0;
LivesScript.livesCounter--;
PlayDeathSound();
System.Timers.Timer timer = new System.Timers.Timer();
timer.Interval = aSDeath.clip.length * 1000;
timer.Start();
timer.Elapsed += delegate
{
timer.Stop();
if (LivesScript.livesCounter > -1)//to get 0 live
{
Debug.Log("TIMER");
var currentScene = SceneManager.GetActiveScene();
SceneManager.LoadScene(currentScene.name);
}
else
{
//TO DO GameOver
}
};
}
As you can see, to make sure the timer REALLY fires, I set up a "debug.Log("TIMER")" to see, if it really works. And guess what: it does. The debug now shows "TIMER" in its console. But you know what doesnt work anymore? The two lines of code right beneath that.
var currentScene = SceneManager.GetActiveScene();
SceneManager.LoadScene(currentScene.name);
It's the same exact lines that worked just before - but when fired from the timer, they just get ignored? How is this even possible?
When I change it all back, it works again. Only when the timer fires the two lines, they get ignored.
This is totally odd or am I missing something? Thank you!
Okay I am not an expert on C# and delegate but apparently it creates a separate thread and you can only use SceneManager.GetActiveScene on main thread.
Since i am not so sure about delegate i will offer an easier solution. You can use a coroutine since you know how much you have to wait like this:
public void Death()
{
StartCoroutine(DeathCoroutine());
}
IEnumerator DeathCoroutine()
{
AddCoinScript.coinCounter = 0;
LivesScript.livesCounter--;
PlayDeathSound();
// wait for duration of the clip than continue executing rest of the code
yield return new WaitForSeconds(aSDeath.clip.length);
if (LivesScript.livesCounter > -1)//to get 0 live
{
Debug.Log("TIMER");
var currentScene = SceneManager.GetActiveScene();
SceneManager.LoadScene(currentScene.name);
}
else
{
//TO DO GameOver
}
}
What about using a coroutine ? You just start it when the player dies, and yield while your sound is still playing.

html5 audio tag playing audio when it is load audio

i have html5 audio player like play, pause, stop buttons.
function onUpdate()
{
var isPlaying = (!getAudioElement().paused);
document.getElementById("playerplay").style.display = (isPlaying)?"none":"block";
document.getElementById("playerpause").style.display = (isPlaying)?"block":"none";
};
function getAudioElement()
{
return document.getElementById("id_audio_element");
}
function play() {
getAudioElement().play();
onUpdate();
}
function pause() {
getAudioElement().pause();
onUpdate();
}
function stop() {
getAudioElement().pause();
getAudioElement().currentTime=0;
onUpdate();
getAudioElement().load();
}
And audio tag:
<audio id="id_audio_element" onended="onUpdate();load();"><source src="105.ogg" type="audio/ogg"></audio>
it works all on browsers perfectly, exept iPhone and iPad's Safari and Chrome. When I call load() , audio starts playing, although I don't call play().
Anybody has a solution? Thanks!
If the source is not changing, there is no need to call load(). If it is changing, try calling pause() after it loads.