SoundEffectInstance and progress bar - windows-phone-8

In my WP application I'm playing a lengthy sound effect and i am trying to
update progressBar with song state, but I just can't find a way, any help would
be appreciated.
My sound is standard SoundEffectInstance sound;
and:
if (sound.State == SoundState.Paused)
{
sound.Resume();
}
else
{
try
{
sound.Stop();
}
catch { }
Stream stream = TitleContainer.OpenStream("Sounds.wav");
var effect = SoundEffect.FromStream(stream);
sound = effect.CreateInstance();
FrameworkDispatcher.Update();
sound.Play();
}

If you have any way to get the length of the sound, either in bytes or units of time, you can use that value. Just compare the number of bytes streamed or the amount of time elapsed (depending on which you can get) to the total, and set the loading bar accordingly.

Related

[AS3]How to quickly mix two audio tracks

There are few answers which mix two audio tracks with sampleDataEvent listener while playing the entire sound. Is there any way to mix the tracks as fast as possible? (The tracks are of equal duration and is in the form of ByteArray)
In the post below
Programatically Mixdown of audio tracks (no playback)
the author suggests using Event.EnterFrame. However, I'm not quite familar with AS3's API. Can anyone give some example code? Thanks!
If you don't need to output the mix in binary format, just do double play.
track1.play();
track2.play();
Yep, as your tracks are in ByteArrays, first make two Sound object and get the data from bytearrays by loadPCMDataFromByteArray().
UPDATE: Since you don't want playback at all, the most simple way to mix the two tracks will be reading one float out of each ByteArray, then write their average into the resultant ByteArray. Using the ENTER_FRAME listener is worth it if you don't want to have your SWF stall while doing the conversion. You've said your arrays are of equal length, if so, the following code snippet should do your "simple mix" of those wavs:
var f1:Number;
var f2:Number;
b1.position=0;
b2.position=0;
var result:ByteArray=new ByteArray();
var l:int=b1.length; // cache property
var i:int=0;
while (i<l) {
i=i+4; // size of float
f1=b1.readFloat();
f2=b2.readFloat();
result.writeFloat(0.5*f1+0.5*f2);
}
Doing an enterframe approach requires your result be available between listener calls, and positions unaltered, with a temporary counter running in the loop which will control "enough converting in this frame". Like this:
var result:ByteArray;
var tracks:Vector.<ByteArray>=[];
var mixFinished:Function; // a callback
function startMixing():void {
// just make it start mixing
for (var i:int=tracks.length;i>=0;i--) tracks[i].position=0;
addEventListener(Event.ENTER_FRAME,doMixing);
result=new ByteArray();
}
function doMixing(e:Event):void {
if (tracks.length==0) {
removeEventListener(Event.ENTER_FRAME,doMixing);
return;
} // sanity check
var mixrate:Number=1.0/tracks.length;
for (var i:int=0;i<2048;i++) { // adjust number accordingly
var tm:int=0; // how many tracks mixed
var f:int=0;
for (var j:int=tracks.length-1;j>=0;j--) {
if (tracks[j].position<tracks[j].length) {
// this track isn't finished
tm++;
f+=tracks[j].readFloat();
}
}
if (tm==0) { // all tracks reached end, stop mixing
removeEventListener(Event.ENTER_FRAME,doMixing);
if (mixFinished!=null) mixFinished(); // do a callback
return;
}
result.writeFloat(f*mixrate);
}
}
With this, you fill tracks, set up mixFinished and call startMixing, then wait until mixFinished would get called, by that time your sound should be mixed properly. If you feel your mixing process should go faster, increase the 2048 value in code appropriately.

LIBGDX: How can i tell when a sound has finished playing?

The Sound API seems to be missing a function to indicate that a sound is finished playing. Is there some other way of finding out if the sound is done?
Not without submitting a patch to libgdx as far as I know the underlying Sound Backends for both OpenAL and Android don't even track the information internally, though the Music API has an isPlaying() function and getPosition() function as per the documentation.
just set this
sound.setLooping(false);
this way it will not run again and again.
and to check whether sound is playing or
not do this.
make a boolean variable
boolean soundplaying;
in render method do this
if(sound.isPlaying()){
soundplaying =true
}
and make a log
gdx.app.log("","sound"+soundplaying);
You can track this by storing the sound instance id that e.g. play() and loop() return. Example code:
private Sound sound;
private Long soundId;
...
public void startSound() {
if (soundId != null) {
return;
}
soundId = sound.loop(); // or sound.play()
}
public void stopSound() {
sound.stop(soundId);
soundId = null;
}
If you didn't want to have to call stopSound() from client code, you could just call it from startSound() instead of the return, to ensure any previous sound is stopped.

Play sound at certain playProgress or videoTime with greensock?

I'm using greensock LoaderMax to load video files and sound files. I've copied as much code as is available to me. A video (s9) is playing and at a certain percentage through the video, I need to play another sound.
if(s9.playProgress > .1) // This is what I can't get to work
{
s12_sound.playSound(); //This sound won't play at .1 playProgress
}
s9.content.visible = true;
s9.playVideo();
stop();
s9.addEventListener(VideoLoader.VIDEO_COMPLETE, play_s9_loop); //This plays a video once s9 is done.
function play_s9_loop(event:Event):void
{
s9.content.visible = false;
s9_loop.content.visible = true;
s9_loop.playVideo();
}
I'm guessing you just can't do an if() on playProgress? Furthermore, I suck at AS3.
You should be able to just listen for the INIT event on the video (which typically means it has loaded enough to determine the duration of the video) and then add an AS cue point.
//...after you create your VideoLoader...
myVideoLoader.addEventListener(LoaderEvent.INIT, initHandler);
myVideoLoader.load();
function initHandler(event:LoaderEvent):void {
myVideoLoader.addASCuePoint( myVideoLoader.duration * 0.1, "myLabel" );
myVideoLoader.addEventListener(VideoLoader.VIDEO_CUE_POINT, cuePointHandler);
}
function cuePointHandler(event:LoaderEvent):void {
trace("Hit the cue point " + event.data.name);
s12_sound.playSound();
}
Also make sure that you preload that s12_sound so that it's ready to play when you need it. Otherwise, you can call playSound() all you want and it ain't gonna happen :)
I haven't used this class before but after reading the docs it looks like you can do something like this:
http://www.greensock.com/as/docs/tween/com/greensock/loading/VideoLoader.html
var mid:Number = s9_loop.duration/2; //get the midpoint using the duration property
s9_loop.addASCuePoint(mid, "middle") //using addASCubePoint to add a cuepoint to the midpoint of the video
s9_loop.addEventListener(VideoLoader.VIDEO_CUE_POINT, handleMidpoint); //listen for the cuepoint
Inside the handler function
protected function handleMidpoint(e:Event):void{
//play your sound
}

Using AS3WavSound to play WAV - cannot stop instantly

I'm using the AS3WavSound (http://code.google.com/p/as3wavsound/) class to playback externally loaded wavs. This is working successfully. The library is simple and effective.
After decoding the Wav ByteArray the method the library employs for playback is using the SampleDataEvent.SAMPLE_DATA event and then writing the mixed samples to the output stream.
player.addEventListener(SampleDataEvent.SAMPLE_DATA, onSamplesCallback);
private function onSamplesCallback( evt : SampleDataEvent ):void
{
for (var i:int = 0; i < samplesLength; i++)
{
if(_mute == false){
outputStream.writeFloat(samplesLeft[i]);
outputStream.writeFloat(samplesRight[i]);
}
}
}
My problem is that I need to silence this audio output immediately but whatever method I have tried there is a distinct (1 second approx) delay before the silence takes effect.
As you can see I've attempted to add a boolean to block any samples being written to the output stream but this has had no effect on the delay.
My suspicion is that this is a fundamental part of how the samples are buffered and then written out. Essentially by the time a user action on screen (clicking a mute button) has been called and the _mute boolean is set to true there are already samples waiting to be written to the output that cannot be affected.
Any advice or confirmation of my suspicion would be greatly appreciated.
Thanks,
gfte.
Your suspicion is probably right - but why stop it at that level? If you want to turn off the sound, would it not be better to set the volume on the soundTransform-property on the SoundChannel-object returned by the play method? (I assume the wav library returns this in some way)
It looks like the library you are using has a similar design to the native Flash Sound API wherein a SoundChannel object is returned from the play() method. This SoundChannel instance has a stop() method which should stop the sound right away.
var sound:WavSoundPlayer = new WavSoundPlayer();
var channel:WavSoundChannel = new WavSoundChannel();
sound.addEventListener( SampleDataEvent.SAMPLE_DATA, onSampleData );
channel = sound.play();
private function onSamplesData( evt : SampleDataEvent ):void
{
for (var i:int = 0; i < samplesLength; i++)
{
outputStream.writeFloat(samplesLeft[i]);
outputStream.writeFloat(samplesRight[i]);
}
}
channel.stop()
The _mute variable in your example will only be able to change either before or after the loop, not while it is looping.

how can i start a video from a specific second in as3

i have a problem about action script 3. i have a flv video and its totaltime is 6 seconds. i want to start it from 2. seconds with seekSeconds(). if i write bigger than 6 values in seekSeconds it will only play the video from head to end.İf i write smaller than 6 ,it won't work.what can i write in seekSeconds() to start the video from 2 seconds?
function useParams()
{
var obj:Object = new Object();
var j;
for (j in this.myParams)
{
if (j == "url")
{
src = this.myParams[j];
}
else if (j=="bas")
{
startTime = int(this.myParams[j]);
}
else
{
stopTime = int(this.myParams[j]);
}
txt.text += j + " - " + this.myParams[j];
}
//fk.source = src;
txt.text = String(startTime);
}
fk.addEventListener(VideoEvent.READY, bitti);
function bitti(eventObject:VideoEvent):void
{
//fk.play();
trace(fk.totalTime);
fk.seek(2);
trace(fk.playheadTime);
//trace(fk.playheadTime);
}
According to the documentation for VideoPlayer, Event.READY is dispatched:
Event dispatched when an FLV file is loaded and ready to display. It starts the first time you enter a responsive state after you load a new FLV file with the play() or load() method. It starts only once for each FLV file that is loaded.
It is possible the video is ready but it hasn't buffered to an adequate amount for seeking. You can change the bufferTime to a value greater than 2 although I am not certain that will guarantee Event.READY will get fired at the time you need. Also note the property of seek for progressive downloads:
For a progressive download, you can seek only to a keyframe; therefore, a seek takes you to the time of the first keyframe after the specified time.
So make sure you set a bufferTime that is adequately advanced passed 2 seconds to ensure you are passed a keyframe.
Note: there is a bufferTime on both a VideoPlayer and the NetStream so you may have to adjust one or the other or both.