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.
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.
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/
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);
}
});
}
Is there any possibility to programatically close Silverlight application on Windows Phone 7?
If you write an XNA Game, you will have access to an explicit Exit() method. If you are writing traditional Silverlight project, then NO, there is no way to programatically close your app. See also Peter Torr's Blog entry on Exiting Silverlight Apps in Windows Phone 7. There he also mentions the option of throwing an unhandled exception, which IMO is a terrible programing style.
An option you may try, is using the WP7 Navigation Service to programatically navigate back out of the application. Not sure if that would work though. Why do you need to Exit?
You can always call an exit by doing this at your landing page use this code on click of your application back button:
if (NavigationService.CanGoBack)
{
while (NavigationService.RemoveBackEntry() != null)
{
NavigationService.RemoveBackEntry();
}
}
This will remove back entries from the stack, and you will press a back button it will close the application without any exception.
Short answer for Silverlight is No.
You should not provide a way to close the applicaiton. Closing the applicaiton should be the users choice and implemented by using the back button the appropriate number of times. This is also a marketplace requirement.
That said, a silverlight application will close if there is an unhandled exception. I have seen a few people try and create programmatic closing by throwing a custom error which is explicitly ignored in error handling. This can work but there is still the marketplace issue.
XNA applications can explictly call Exit().
Some good info here already. Adding to this..
The platform is fully capable of managing closure of apps. The more apps don't provide an exit, the quicker users will become accustomed to not thinking about app house keeping, and let the platform manage it.
The user will just navigate their device using start, back, etc.
If the user wants out of the current app to go do something else quickly - easy - they just hit start.
.Exit(), whilst available for xna, really isn't required anymore either. There was a cert requirement during CTP that games had to provide an exit button. This is now gone.
Non game apps never had the need to implement this.
The more this topic's discussed (and it really has been given a good run around the block), the more the indicators to me suggest there is no need to code an exit.
Update: For those thinking of an unhandled exception as a suitable way of closing an app intentionally or letting the app close due to subpar operating conditions, I would recommend reviewing the comments concerning Application Certification Requirements in this answer. Is there a way to programmatically quit my App? (Windows Phone 7)
Here is another solution.
If you have an error page that i.e. displays error to the end user you can use the
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
base.OnBackKeyPress(e);
e.Cancel = true;
}
And you can instruct user to press start button to exit application.
Add a reference to Microsoft.Xna.Framework.Game, then call:
new Microsoft.Xna.Framework.Game().Exit();
private void PhoneApplicationPage_BackKeyPress(object sender, System.ComponentModel.CancelEventArgs e)
{
while (NavigationService.CanGoBack)
NavigationService.RemoveBackEntry();
}
That works for me fine.
You can close the app using this statement
Application.Current.Terminate();
This worked perfectly on Windows phone 7
System.Reflection.Assembly asmb = System.Reflection.Assembly.Load("Microsoft.Xna.Framework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553");
asmb = System.Reflection.Assembly.Load("Microsoft.Xna.Framework.Game, Version=4.0.0.0, Culture=neutral, PublicKeyToken=842cf8be1de50553");
Type type = asmb.GetType("Microsoft.Xna.Framework.Game");
object obj = type.GetConstructor(new Type[] { }).Invoke(new object[] { });
type.GetMethod("Exit").Invoke(obj, new object[] { });
Link - source
My 2 pence worth, reasons for an exit
1) there is no interent connection the first time it is run and it needs to create an account on a web service somewhere to run.
2) You need to force an upgrade for the user, again when tied to a web service, you may discover a bug in your app, or have web service changes that mean the user needs to be forced to upgrade, at that point you will want to inform the user that they must upgrade and then exit the app.
Currently in my app I am forced to take the user to a form that says "they" must exit, and if they click back they are again forced back to this page. not very nice.
In Silverlight, I throw an un-handled exception when I have to exit the application. I know that this isn't the graceful method to handle this but it is still the most convenient and easiest solution.
I know that according to the guidelines there shouldn't be any un-handled exceptions in the code but I write why I am explicitly throwing an un-handled exception in the Exception Request document at the time of submission.
Till now this method has always worked and never failed me.
Easiest way to do this is to add a reference to Microsoft.Xna.Framework.Game, then add
using Microsoft.Xna.Framework.GamerServices; before namespace. Then we have a button in our Example.xaml with Click="quit_button". In out Example.xaml.cs we put this code inside our page-class:
private void quit_Click(object sender, EventArgs e)
{
new Microsoft.Xna.Framework.Game().Exit();
//This will close our app
}
var buttonInfo = MessageBox.Show("Are you sure you want to exit?", "Exit", MessageBoxButton.OKCancel);
if (buttonInfo == MessageBoxResult.OK)
{
if (NavigationService.CanGoBack)
{
while (NavigationService.RemoveBackEntry() != null)
{
//
}
}
e.Cancel = false;
}
else
{
//Stop page from navigating
e.Cancel = true;
}
Navigate to App.xaml.cs in your solution explorer and
add a static method to the App class
public static void Exit()
{
App.Current.Terminate();
}
so that you can call it anywhere from your application , as below
App.Exit();