Audio volume change is lagging - unity3d

Im playing two tracks in sync. This works well, they sound like one song.
What im trying to do is allow player to switch one track on and of by toggling mute or setting volume to 0 or 1. The muted track continues playing in sync with other track but cant be heard.
But the volume change /muting is lagging. So even if you switch the sound on exactly on beat you wont hear that beat cause it takes a split second for the code to react. There must be a way to make the change instant?
Below is a part of the music manager that handles this. The full code also includes how sound is loaded and starts playing and can be seen here:
https://github.com/Lautaro/AudioTest/blob/master/Assets/MusicManager.cs
// Update is called once per frame
void Update()
{
if (Input.anyKeyDown)
{
if (Input.GetKeyDown(KeyCode.Space))
{
Toggle();
}
}
}
void Toggle()
{
var clip = Sources.First(s => s.clip.name == "ExtraBeat");
// Same result if setting clip.volume instead of mute
clip.mute = !clip.mute;
}
The complete project with audio tracks can be cloned here. Use space to toggle sound.
https://github.com/Lautaro/AudioTest.git

Related

Unity VideoPlayer and WebGLMovieTexture cant play two videos in a row

I'm trying to play videos in Unity WebGL in the browser, but having lots of problems.
I tried two different video players and none of them work fully.
The WebGLMovieTexture player works like this
public WebGLStreamingVideoPlugin _videoPlugin = new WebGLStreamingVideoPlugin("http://www.example.net/video.mp4");
_videoPlugin.Play();
Basically when you want to play a video you create a new instance and give it the URL like above, and it plays great!!
The problem is when you want to stop that video, and play a different video, it seems impossible because there is no way dispose of the first video because there is only a Stop() in the API, which stops the playback but it continues to stream the video data from the internet in the background.
There is no way to delete the instance because Destroy() cant be called since that WebGLMovieTexture is not derived from monodevelop, and C# does not seem to give a way to delete an object (how silly). Even setting it to null doesnt do it, it continues to stream the video in the background.
So if you create a new instance in order to play a different video, you end up with TWO video streams, and if you do it again to play a third, you end up with THREE, and so on, so quickly you can see how bad that will end up.
My question is how to dispose of or destroy the first WebGLMovieTexture player, or maybe tell it to stop streaming the first video and start playing a different one?
The second player I tried is the VideoPlayer for WebGL in Unity Version 5.6.0b4, with this one I can only get it to play a video if I hardcode the URL in the inspector, if I put the URL in code it doesn't play it in the browser.
vPlayer = gameObject.GetComponent<UnityEngine.Video.VideoPlayer>();
if (vPlayer.isPlaying) {
Debug.Log("STOPPING PLAY");
vPlayer.Stop();
}
vPlayer.url = url;
vPlayer.isLooping = true;
vPlayer.frame = 0;
vPlayer.targetCameraAlpha = 1F;
vPlayer.Prepare();
vPlayer.Play();
And to get it to play a second video I suspect I will have the same problems as the other one.
Anybody have any ideas that can help me?

SKAudioNode play sound once

I can't seem to find much information about SKAudioNode. How do i play a sound only once? I do not want to repeat the sound.
What i am trying to accomplish is to play a short laser sound each time a bullet spawns, in spritekit.
Unfortunately, what #KnightOfDragon says is not correct (but I do not have enough reputation to comment).
SKAudioNode has been introduced in iOS 9 and is meant as a replacement for SKAction.playSoundFileNamed(...) as it is much more powerful (You can add it as a child to a SpriteKit SKNode and if the attribute positional is set to true, 3D audio mixing is added automatically).
In order to play a sound once with SKAudioNode use the following code:
if #available(iOS 9, *) {
let pling = SKAudioNode(fileNamed: "pling.wav")
// this is important (or else the scene starts to play the sound in
// an infinite loop right after adding the node to the scene).
pling.autoplayLooped = false
someNode.addChild(pling)
someNode.runAction(SKAction.sequence([
SKAction.waitForDuration(0.5),
SKAction.runBlock {
// this will start playing the pling once.
pling.runAction(SKAction.play())
}
])
}
else {
// do it the old way
}
Update
Have a look here, how to use Actions on audio nodes: SKAction->Audio-Stuff. The documentation says:
Use SKAction playSoundFileNamed:waitForCompletion: only for short incidentals.
Use AVAudioPlayer for long running background music.
This does not mean, that a SKAudioNode should not be used for one-time audio. With playSoundFileNamed you cannot change the volume or pause/stop playback and so on.
if you are trying to do sound effects, you use SKAction.playSoundFileNamed(...) on the sprite that is creating the effect. SKAudioNode is more for having music playing in your game
Example:
//we have ship as an SKSpriteNode
//lets fire laser
ship.runAction(SKAction.playSoundFileNamed("pewpewpew.caf",waitForCompletion:false));

How do you make an AuGraph restart a audio file from the start of the file?

I am working with Apple's MixerHost application. It is a great example of how to set up an AuGraph, however the stop button is really a pause button. When you hit play it continues playing the sound files from the last position. I want to have a true stop button that causes the play head to move back to the start. I looked up AuGraph in apple's docs but I do not see anything about starting the song over without having to go through the process if creating a brand new graph, and I would prefer not to have to do this since i have a large loading delay.
Figured it out. This was my method
for (int audioFile = 0; audioFile < NUM_FILES; ++audioFile) {
soundStructArray[audioFile].sampleNumber = 0;
}

Music not stopping when moving an app to the background

I am optimizing a game so that when there is an incoming call or if it is moved to the background for any other reason, it should stop the music, timers and pause correctly.
It works great other than the fact that for some reason the music doesn't stop playing even though I issued a command for it to stop. What's weirder is that when the game returns to the foreground there's 2 background musics playing instead of one.
Here is my some of my code, nothing too complicated or out of the ordinary:
...
NativeApplication.nativeApplication.systemIdleMode = SystemIdleMode.KEEP_AWAKE;
NativeApplication.nativeApplication.addEventListener(Event.ACTIVATE, handleActivate);
NativeApplication.nativeApplication.addEventListener(Event.DEACTIVATE, handleDeactivate);
...
private function handleActivate(event:Event):void
{
stage.frameRate = previousFrameRate;
//if the music was on when the game is moved to the background, then replay it when its moved back to the foreground
if(musicOn)
{
BGMusic.play();
}
}
private function handleDeactivate(event:Event):void
{
BGMusic.stop();
stage.frameRate = 0;
}
It is worth noting that if I don't replay the music when then game returns to the foreground (i.e. when I don't use BGMuusic.play() in handleActivate), there won't be any music as expected. It is only when I stop the music AND resume it later when moving to the foreground that the background music doesn't stop and I get two playing tracks.
Any ideas? As I said, everything else works fine, and the game correctly pauses. I am testing this on Flash builder Emulator since I don't have the necessarily certificates to test it directly on the iphone. So maybe it is a problem with the emulator itself rather than the code.
Thanks in advance
EDIT: Am writing this with flash and adobe air
Well that was stupid of me. Everything is working fine I just forgot to add another condition to the if statement. So instead of:
if(musicOn)
{
BGMusic.play();
}
It should be
if(musicOn && !BGMusic.isPlaying())
{
BGMusic.play();
}
Everything works fine now...I will change the variable name of musicOn to something clearer like musicButtonOn.
Anyways thanks for help. If you have any tips or comments feel free to tell me =D
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag {
NSLog(#"Playing stoped");
[player stop];
}

Simple sound effect loop using AudioToolKit

I've created a few sounds for use in my game. I can play them at certain events without issue:
// create sounds
CFBundleRef mainBundle;
mainBundle = CFBundleGetMainBundle();
_soundFileShake = CFBundleCopyResourceURL(mainBundle, CFSTR("shake"), CFSTR("wav"), NULL);
AudioServicesCreateSystemSoundID(_soundFileShake, &_soundIdShake);
// later...
AudioServicesPlaySystemSound(_soundIdShake);
The game has a mechanism which allows you to shake the device to activate some functionality. I've got the shaking code done so I get get a "shaking started" and "shaking ended" message to my game. What I need to have happen is start playing "shave.wav" when shaking starts and loop it until it stops. Is there a way to do this with AudioToolbox/AudioServices? How could I do this if not?
Keep track of the "is shaking" state and register a callback for system sound completion with AudioServicesAddSystemSoundCompletion. Then just start the system sound again whenever it completes AND the device is still being shaken. If the sound is short enough, this will create the desired effect. If you need to ensure the sound stops immediately when the shaking stops, you'll need to use one of the sound APIs that provides more granular control over playback (e.g., Audio Queue Services or AVAudioPlayer).