SoundEffect and SoundEffectInstance when in Windows Phone Silverlight app - silverlight

Windows Phone 7.1/7.5/Mango Silverlight app.
I used the Sound Sample example here to implement playing sounds in my app.
Here's the snippet.
//The sounds to play
private SoundEffect coyoteSound;
private SoundEffect birdSound;
//Constructor
public MainPage()
{
InitializeComponent();
// Prime the pump or we'll get an exception.
FrameworkDispatcher.Update();
// Create and load SoundEffect objects.
LoadSound("Resources/coyoteSound.wav", out coyoteSound);
LoadSound("Resources/birdSound.wav", out birdSound);
}
/// <summary>
/// Loads a wav file into an XNA Framework SoundEffect.
/// </summary>
/// <param name="SoundFilePath">Relative path to the wav file.</param>
/// <param name="Sound">The SoundEffect to load the audio into.</param>
private void LoadSound(String SoundFilePath, out SoundEffect Sound)
{
// For error checking, assume we'll fail to load the file.
Sound = null;
try
{
// Holds informations about a file stream.
StreamResourceInfo SoundFileInfo = App.GetResourceStream(new Uri(SoundFilePath, UriKind.Relative));
// Create the SoundEffect from the Stream
Sound = SoundEffect.FromStream(SoundFileInfo.Stream);
}
catch (NullReferenceException)
{
// Display an error message
MessageBox.Show("Couldn't load sound " + SoundFilePath);
}
}
//Play sound when page naivgateTo
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgse)
{
birdSound.Play();
}
//Common mouseclick handler to play sound
private void ElementClick_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
FrameworkElement ele = sender as FrameworkElement;
if (ele != null)
{
switch (ele.Name)
{
case "imgcoyoteSound":
coyoteSound.Play();
break;
case "imgbirdSound":
birdSound.Play();
break;
default:
birdSound.Play();
break;
}
}
}
Questions:
1: I want to Stop the sound and I see I need to use SoundEffectInstance for that. What is the best way to integrate those in my above code.
2: The sound in the OnNavigatedTo starts playing even before my page is loaded? I tried putting the play in OnLoaded but still the say. Any ideas on that?
3: I read about being careful on Memory Usage when using SoundEffect/SoundEffectInstance. Will the above code cause any memory issue?
4:Most of my pages (20-25) will have sound effects implementation like above. That shouldn't be an issue correct?
Update: Is is right place to call dispose? Will it affect the sound play when I go to this page using Back button?
//Play sound when page naivgateFrom
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgse)
{
birdSoundEffectInstance.Dispose();
coyoteSoundEffectInstance.Dispose();
}

SoundEffectInstances are fairly simple to implement, assuming silverlight works like regular XNA.
SoundEffectInstance birdSoundInstance = birdSound.CreateInstance();
Usage of a SoundEffectInstance is similar to a SoundEffect, except with a lot more control. You can choose stereo panning position, pitch and volume, set the sound to loop, pause the sound, etc. Just keep a reference to the Instance around and use one of its methods for these actions. I would recommend just adding a birdSoundInstance and coyoteSoundInstance alongside your SoundEffects in class properties, I guess.
Memory is not as much of an issue on Windows Phone because the platform limits you to 16 SoundEffectInstances playing at once. So, essentially, it won't let you use large amounts of memory (unless you're playing 16 very large sounds). What I like to do is make a singleton for playing music which has an array of 16 sounds. When I call .PlaySound(SoundEffectInstance sound), it checks for an empty spot in the array to place that sound in. If there is none, it replaces the oldest sound. It checks every frame for stopped (ended) sounds in the array and flushes them out, disposing them. (A Queue might seem like a good data structure to do this, but it is restrictive about removing sounds which have ended).
Another thing to note when using SoundEffectInstances is that they continue to exist even if you dereference them, in my experience. If you want to stop playing an instance you need to either let it finish or command it to stop. Note that SoundEffectInstance has a Dispose() method. Use this when you are done playing the sound to remove it from memory. I don't think the garbage collector automatically picks them up like most other assets.
I'm not sure I can help with your code as it seems Silverlight asset loading is significantly different from XNA pipeline loading, but I hope I've shed some light on the subject. I think sounds are some of the easier things to do in XNA.

Related

Extend GoBack function in NavigationWindow

I´ve a NavigationWindow with some pages. I navigate from one to another with buttons, and go back function of navigation window. My problem is I use a descriptor in some of the pages when they load, and I´d like to dispose it when you use go back function in navigationwindow (in fact the "descriptor" is Kinect, and when the page loads, it starts Kinect with sensor.start(), and I want to stop it when going back, sensor.stop()... but I think it´s the same as a file descriptor for this issue and much more people has worked with file descriptors).
Is there any way to extend the GoBack function in the page to dispose descriptors (in my code I only need to call sensor.stop(); )?
Thanks in advance
My suggestion in the comment was based on windows phone development experience.. but after i tried applying that solution in wpf using navigationwindow, i found nothing like OnNavigatedTo/OnNavigatedFrom in WP/silverlight.
But i found Navigating event of NaviagtionWindow can be used instead. In that event, you can get this.CurrentSource which is Page2 (if you navigate back from Page2 to Page1) and dispose descriptors in that Page.
Hope this work.
Ok, I found how to do a workaround. It also applies to the question: how to dispose an object in WPF. It´s weird all posts about dispose objects in WPF talk about GC and that you can´t dispose it yourself. Yes, GC dispose objects automatically, but when he wants. But maybe you want to dispose inmediately, or you have an object that needs previous operations before dispose. In my case, Kinect needs to be stopped before dispose (you can dispose without stopping, but kinect ir sensor is still working). And GC is not solution because I need to stop it before dispose.
So, the solution:
public partial class MyClass : Page
{
private KinectSensor sensor;
public MyClass()
{
InitializeComponent();
this.Loaded += (s, e) => { NavigationService.Navigating += NavigationService_Navigating; };
// What you want to add to the constructor
// I want to start Kinect
sensor = KinectSensor.KinectSensors.FirstOrDefault(k => k.Status == KinectStatus.Connected);
sensor.Start();
}
public void NavigationService_Navigating(object sender, NavigatingCancelEventArgs e)
{
if (e.NavigationMode == NavigationMode.Back)
{
// What you want to do.
// I want to stop and dispose Kinect
if (sensor != null)
{
sensor.Stop();
sensor.Dispose();
}
}
}
}

Silverlight MP3 Playing Library

I'm trying to play MP3 files in SilverSprite, and it's super buggy. Is there an alternative library I can use to play MP3s in Silverlight?
Edit: Now that there's a bounty, I'm specifically looking for something that:
Works with SL 3-4
Is a separate project/DLL
Will work in SilverSprite projects (I'm using a layer on top of SS) -- no GUI, just methods I can call to play sounds
Works with content that has the build action set to Content. I cannot use embedded resources due to a bug in SilverSprite. My app will not run.
Plays MP3s.
Can play multiple audio files at the same time
I hope it's clear what I'm trying to find. I would like something I can embed in my own game engine, which sits on top of SilverSprite. I will supply all the audio files in the XAP. (The SilverSprite audio is quite broken and doesn't work.)
Update: The specific direction I would probably like to go in is to instantiate a new MediaElement, set the source, and play it. I have some code below, but a) NaturalDuration.TimeSpan.TotalMilliseconds reports 0, and b) the .MediaOpened never triggers.
MediaElement m = new MediaElement();
m.Source = new Uri("Content/Audio/chimes.mp3", UriKind.Relative);
m.Stop(); // useless?
//m.SetSource(new FileStream("Content/Audio/chimes.mp3", FileMode.Open)); // "Permission denied" exception, is it even finding the file?
m.Volume = 1; // Max
m.Position = TimeSpan.FromMilliseconds(0);
while (m.CurrentState != System.Windows.Media.MediaElementState.Closed)
{
Thread.Sleep(10);
}
m.MediaOpened += (sender, e) =>
{
m.Play();
};
m.Play();
For some working code rather similar to your updated approach see http://www.wiredprairie.us/blog/index.php/archives/577 . Beware that the MediaElement needs to be added to the control/component tree - see http://www.michaelsnow.com/2010/12/17/playing-sound-effects-on-windows-phone-7/.
Two very interesting options for your requirements is this library and this one.
For this kind of stuff you could also implement/use a custom MediaStreamSource like this one... see here and here.
EDIT - some other options:
Playing multiple sounds in parallel via XNA see source code at http://create.msdn.com/en-US/education/catalog/sample/silverlightsound
Using MediaPlayer class from XNA 4 for example:
MediaPlayer.Stop();
MediaPlayer.Volume = 1;
MediaPlayer.Play(Song.FromUri("TestSound", new Uri("/Content/Audio/chimes.mp3", UriKind.Relative)));
As for playing multiple sound files at the same time:
IIRC this is something which could cause your app to fail validation.

How Do I Add Background Thread To Silverlight Custom Control?

I'm building a custom control for Windows Phone 7+ that can do augmented reality image processing. The control works wonderfully in practice (when I run the app), but because I have the image processing running on a separate thread, it breaks when I try to open the page in Blend or the Visual Studio designer.
Here's an example of the thread I'm trying to run (basically taken from http://msdn.microsoft.com/en-us/library/hh202982(v=vs.92).aspx) :
public override void OnApplyTemplate()
{
// assigning template stuff, initializing my camera
_myManualResetEvent = new ManualResetEvent(true);
_myCameraProcessingThread = new System.Threading.Thread(ProcessingMethod);
_myCameraProcessingThread.Start();
}
void ProcessingMethod()
{
int[] myBuffer = new int[640 * 480];
while(_someCondition)
{
_myManualResetEvent.WaitOne();
_myCamera.GetPreviewBufferArgb32(myBuffer);
// do my processing stuff
_myManualResetEvent.Set();
}
}
This breaks the ever-loving heck out of Blend. Would love to know why.
It looks like you are doing a lot of run-time stuff in the OnApplyTemplate method.
This will get called when Blend or Visual Studio instantiates the design view of your control.
You should either check to see if you are in design mode using the DesignMode:
if (!DesignMode)
{
_myManualResetEvent = new ManualResetEvent(true);
_myCameraProcessingThread = new System.Threading.Thread(ProcessingMethod);
_myCameraProcessingThread.Start();
}
or move this code into a method/event handler that only gets called when the application actually runs.

play beep in silverlight

I am trying to make a small application for learning Morse code and I am stuck because I do not know how to play a Beep in Silverlight.
How can I do something like?
Console.Beep(Freq, elementLength)
(I have made a console application that uses Console.Beep and it does not work very well (for 20word per minute the dot length is 60ms and the space between 2 signs is 180ms so for letter s witch is ... (3 dots) in my headphones I hear poc! not a clear sound)... I suppose the solution is to use DirectX/XNA)
Can you please advise me how to make the application beep and if xna is the solution can you please direct me to a tutorial (I did not figure out what sdk I need to install and from where to download)
Thank you
There is no direct "beep" in silverlight, that I'm aware. However, you have a plethora of sound capabilities; one of which is using the MediaElement control. So, you could add one of those to your page:
<MediaElement x:Name="beeper"></MediaElement>
Then in your code behind you can assign and call the sound:
private void AssignBeep()
{
Uri beepUri = new Uri("Project;component/beep.mp3", UriKind.RelativeOrAbsolute);
StreamResourceInfo streamInfo = Application.GetResourceStream(beepUri);
this.beeper.SetSource(streamInfo.Stream);
this.beeper.AutoPlay = false;
}
Then you can call it for a beep:
private void PlayBeep()
{
this.beeper.Position = new TimeSpan(0,0,0,0);
this.beeper.Volume = 1;
this.beeper.Play();
}
Credits to forums.silverlight.net
Look at this.. i think this is what you need..
http://silversynth.codeplex.com/

How to get rid of the "click" sound at end of translation in Microsoft Translate API in Silverlight app

I am using the MS Translator to send back a WAV file of text to enable "talking" in my Silverlight 4 app.
However, at the end of every translation, there is a wierd click noise (it sounds like someone is turning a microphone on or off).
Here is an online Silverlight app which demonstrates the issue. Type something in and translate it (can be the same language) and listen to the end of the talking.
Is there anything I can do to get rid of this noise? I was thinking of reading the WAV file to 90% and then stopping it before the sound but I would like to understand technically why it's coming back with the noise and where the problem is so I can find the best solution for it.
UPDATE: After Brad's useful lead below it seems that the problem is in the WaveMediaStreamSource that converts the returned WAV into a format that Silverlight can use.
This is the same one mentioned/used in the online project here.
So... any idea how to get rid of the crackling sound when WaveMediaStreamSource converts it?
I'm not sure if this is helpful, but it seems that the click noise isn't in the WAV file itself.
I used Fiddler to dig out the response coming back from the server and saved that to a WAV file. Opening that in Audacity, I can clearly hear the translation to the end... no click.
So, that click might be the normal sound of the component in Silverlight stopping. However, I have a different theory.
The WAV file itself is sampled at 8kHz. That's kind of an oddball. I bet the click noise is an artifact of the sound card or software (silverlight/audio driver/windows itself, etc.) up-sampling to a more appropriate rate. This is testable. Try making a WAV file and use Fiddler or some other HTTP proxy tool to return your WAV instead of what was requested from the Microsoft server. See if your WAV (at 44.1kHz for example) has the same issue.
I had this same problem. I'm sure everyone does. Here is how I solved it.
Basically I added a marker to the stream that performed the callback 1 second before the audio was finished playing. That callback then fires a timer that is called 700ms later and that method stops the audio (about 300ms) before it's completed. I tried it without this timer and it was inconsistent. It seems like if you set a marker to fire 300ms before the end it wont always fire. Better to get it one second before and then run your own timer to cut it off when you are ready.
Here is the relevant code snippets. Hope it can help someone else. There are loads of other tricks to writing a smooth running audio player but this code should solve at least your clicking issue.
public void Page_Loaded(object sender, EventArgs args)
{
mediaElement.MediaOpened += new RoutedEventHandler(mediaElement_MediaOpened);
mediaElement.MarkerReached += new TimelineMarkerRoutedEventHandler(mediaElement_MarkerReached);
}
Timer t;
void mediaElement_MarkerReached(object sender, TimelineMarkerRoutedEventArgs e)
{
// almost completed playing the file so lets stop before the annoying click is heard
t = new Timer(handleStopTimerDone, "", 700, 0);
}
public void handleStopTimerDone(object state)
{
// stop the audio playing
Stop();
}
private void mediaElement_MediaOpened(object sender, RoutedEventArgs e)
{
TimeSpan duration = mediaElement.NaturalDuration.TimeSpan;
TimelineMarker newMarker = new TimelineMarker();
newMarker.Time = new TimeSpan(duration.Ticks - 10000000);
while (mediaElement.Markers.Count > 0)
{
mediaElement.Markers.RemoveAt(0);
}
mediaElement.Markers.Add(newMarker);
}
public void Stop()
{
this.Dispatcher.BeginInvoke(delegate()
{
mediaElement.AutoPlay = false;
mediaElement.Stop();
mediaElement.Position = TimeSpan.FromSeconds(0);
if (memData != null)
{
WaveMediaStreamSource wavMss = new WaveMediaStreamSource(memData);
mediaElement.SetSource(wavMss);
}
});
}

Resources