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.
Related
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 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 an easy way to dynamically discover all the XAMLs files within all the currently loaded modules (specifically of a Silverlight Prism application)? I am sure this is possible, but not sure where to start.
This has to occur on the Silverlight client: We could of course parse the projects on the dev machine, but that would reduce the flexibility and would include unused files in the search.
Basically we want to be able to parse all XAML files in a very large Prism project (independent of loading them) to identify all localisation strings. This will let us build up an initial localisation database that includes all our resource-binding strings and also create a lookup of which XAML files they occur in (to make editing easy for translators).
Why do this?: The worst thing for translators is to change a string in one context only to find it was used elsewhere with slightly different meaning. We are enabling in-context editing of translations from within the application itself.
Update (14 Sep):
The standard method for iterating assemblies is not available to Silverlight due to security restrictions. This means the only improvement to the solution below would be to cooperate with the Prism module management if possible. If anyone wants to provide a code solution for that last part of this problem there are points available to share with you!
Follow-up:
Iterating content of XAP files in a module-base project seems like a really handy thing to be able to do for various reasons, so putting up another 100 rep to get a real answer (preferably working example code). Cheers and good luck!
Partial solution below (working but not optimal):
Below is the code I have come up with, which is a paste together of techniques from this link on Embedded resources (as suggested by Otaku) and my own iterating of the Prism Module Catalogue.
Problem 1 - all the modules are
already loaded so this is basically
having to download them all a second
time as I can't work out how to
iterate all currently loaded Prism modules.
If anyone wants to share the bounty
on this one, you still can help make
this a complete solution!
Problem 2 - There is apparently a bug
in the ResourceManager that requires
you to get the stream of a known
resource before it will let you
iterate all resource items (see note in the code below). This means I have to have a dummy resource file in every module. It would be nice to know why that initial GetStream call is required (or how to avoid it).
private void ParseAllXamlInAllModules()
{
IModuleCatalog mm = this.UnityContainer.Resolve<IModuleCatalog>();
foreach (var module in mm.Modules)
{
string xap = module.Ref;
WebClient wc = new WebClient();
wc.OpenReadCompleted += (s, args) =>
{
if (args.Error == null)
{
var resourceInfo = new StreamResourceInfo(args.Result, null);
var file = new Uri("AppManifest.xaml", UriKind.Relative);
var stream = System.Windows.Application.GetResourceStream(resourceInfo, file);
XmlReader reader = XmlReader.Create(stream.Stream);
var parts = new AssemblyPartCollection();
if (reader.Read())
{
reader.ReadStartElement();
if (reader.ReadToNextSibling("Deployment.Parts"))
{
while (reader.ReadToFollowing("AssemblyPart"))
{
parts.Add(new AssemblyPart() { Source = reader.GetAttribute("Source") });
}
}
}
foreach (var part in parts)
{
var info = new StreamResourceInfo(args.Result, null);
Assembly assy = part.Load(System.Windows.Application.GetResourceStream(info, new Uri(part.Source, UriKind.Relative)).Stream);
// Get embedded resource names
string[] resources = assy.GetManifestResourceNames();
foreach (var resource in resources)
{
if (!resource.Contains("DummyResource.xaml"))
{
// to get the actual values - create the table
var table = new Dictionary<string, Stream>();
// All resources have “.resources” in the name – so remove it
var rm = new ResourceManager(resource.Replace(".resources", String.Empty), assy);
// Seems like some issue here, but without getting any real stream next statement doesn't work....
var dummy = rm.GetStream("DummyResource.xaml");
var rs = rm.GetResourceSet(Thread.CurrentThread.CurrentUICulture, false, true);
IDictionaryEnumerator enumerator = rs.GetEnumerator();
while (enumerator.MoveNext())
{
if (enumerator.Key.ToString().EndsWith(".xaml"))
{
table.Add(enumerator.Key.ToString(), enumerator.Value as Stream);
}
}
foreach (var xaml in table)
{
TextReader xamlreader = new StreamReader(xaml.Value);
string content = xamlreader.ReadToEnd();
{
// This is where I do the actual work on the XAML content
}
}
}
}
}
}
};
// Do the actual read to trigger the above callback code
wc.OpenReadAsync(new Uri(xap, UriKind.RelativeOrAbsolute));
}
}
Use GetManifestResourceNames reflection and parse from there to get only those ending with .xaml. Here's an example of using GetManifestResourceNames: Enumerating embedded resources. Although the sample is showing how to do this with a seperate .xap, you can do this with the loaded one.
I've seen people complain about some pretty gross bugs in Prism
Disecting your problems:
Problem 1: I am not familiar with Prism but from an object-oriented perspective your Module Manager class should keep track of whether a Module has been loaded and if not already loaded allow you to recursively load other Modules using a map function on the List<Module> or whatever type Prism uses to represent assemblies abstractly. In short, have your Module Manager implement a hidden state that represents the List of Modules loaded. Your Map function should then take that List of Modules already loaded as a seed value, and give back the List of Modules that haven't been loaded. You can then either internalize the logic for a public LoadAllModules method or allow someone to iterate a public List<UnloadedModule> where UnloadedModule : Module and let them choose what to load. I would not recommend exposing both methods simultaneously due to concurrency concerns when the Module Manager is accessed via multiple threads.
Problem 2: The initial GetStream call is required because ResourceManager lazily evaluates the resources. Intuitively, my guess is the reason for this is that satellite assemblies can contain multiple locale-specific modules, and if all of these modules were loaded into memory at once it could exhaust the heap, and the fact these are unmanaged resources. You can look at the code using RedGate's .NET Reflector to determine the details. There might be a cheaper method you can call than GetStream. You might also be able to trigger it to load the assembly by tricking it by loading a resource that is in every Silverlight assembly. Try ResourceManager.GetObject("TOOLBAR_ICON") or maybe ResourceManager.GetStream("TOOLBAR_ICON") -- Note that I have not tried this and am typing this suggestion as I am about to leave for the day. My rationale for it being consistently faster than your SomeDummy.Xaml
approach is that I believe TOOLBAR_ICON is hardwired to be the zeroth resource in every assembly. Thus it will be read very early in the Stream. Faaaaaast. So it is not just avoiding needing SomeDummy.Xaml in every assembly of your project that I am suggesting; I am also recommending micro-optimizations.
If these tricks work, you should be able to significantly improve performance.
Additional thoughts:
I think you can clean up your code further.
IModuleCatalog mm = this.UnityContainer.Resolve<IModuleCatalog>();
foreach (var module in mm.Modules)
{
could be refactored to remove the reference to UnityContainer. In addition, IModuleCatalog would be instantiated via a wrapper around the List<Module> I mentioned in my reply to Problem 1. In other words, the IModuleCatalog would be a dynamic view of all loaded modules. I am assuming there is still more performance that can be pulled out of this design, but at least you are no longer dependent on Unity. That will help you better refactor your code later on for more performance gains.
I'm writing a Media Player using WPF and the MediaElement.
I was playing a video i have that has several audio tracks. But they are both playing at the same time :(
How do i just play one of them ? is it at all possible ?
I think this problem is in the audio and video DirectShow codecs you use. Can you play the video correct in the Windows Media Player? If no, please re-install the appropriated codecs.
Some months ago I have completely prototyped the requirements to switch audio tracks in order to show the video-help in our multi-language software.
My experience shows some alternatives:
Use the WMP-control via WinForms host, and then change the language like:
var control = ((IWMPControls3)wmpControl.Ctlcontrols);
control.currentAudioLanguage = 9; // english
The Complete list of the LCID you can find here.
To list all audio tracks in the video you can use something like:
wmpControl.PlayStateChange += (o, args) => {
if(args.newState == 3) {
var control = ((IWMPControls3)wmpControl.Ctlcontrols);
for(int i = 1; i <= control.audioLanguageCount; i++) {
MessageBox.Show(control.getAudioLanguageID(i) + ": " + control.getAudioLanguageDescription(i));
}
}
};
Use the separate audio tracks and play it synchronously to the video using the MediaPlayer. The main problem of this method is, that you must synchronize audio and video playback, start, stop, seeking,.. manually.
I hope this helps you to choose your solution.
It is not possible with the WPF MediaElement. If you have some DirectShow know-how, you can try my WPF MediaKit and either modify the MediaUriElement/Player or create your own.