WPF SoundPlayer multi-channel sound? - wpf

I have an app that emits sounds at a random interval. When two sounds collide they do not nicely overplay each other but one interrupts the other.
I'm using SoundPlayer to play the sounds. (this is a WPF app)
How can I use multiple sound channels so that if two sounds occur at the same time they are both played at the same time instead of one interrupting the other?

To my knowledge SoundPlayer uses the native PlaySound function which does not support playing multiple sound simultaneously.
You can however do this with System.Windows.Media.MediaPlayer.
var p1 = new MediaPlayer();
p1.Open(new Uri(#"C:\windows\media\ringout.wav"));
p1.Play();
System.Threading.Thread.Sleep(250);
var p2 = new MediaPlayer();
p2.Open(new System.Uri(#"C:\windows\media\ringout.wav"));
p2.Play();
The sleep is there simply to add a bit of a delay to the playback, making it clear that the two sounds do actually play at the same time.

Related

Timers in clojure?

I'm wondering if there is any widespread timer solution.
I want to write a simple game engine which would process users input on tick every 20ms (or perform some actions once after 20ms (or any other period)) and basically update "global" state via transactions, and also I plan to use futures so this solution should be able to deal with concurrency caveats.
Can you give me an advice?
You have actually got two distinct issues here.
The first is the issues of timers. You have lots of choices here:
Start a thread that sleeps between actions, something like (future (loop [] (do-something) (Thread/sleep 20) (when (game-still-running) (recur))))
Use a Java TimerTask - easy to call from Clojure
Use a library like my little utility Task that includes a DSL for repeating tasks
Use the timer functionality from whatever game engine you are using - most of these provide some tools for setting up a game loop
I'd probably just use the simple thread option - it's pretty easy to set up and easy to hack more features in later if you need to.
The second issue is handling game state. This is actually the trickier problem and you will need to design it around the particular type of game you are making, so I'll just give a few points of advice:
If your game state is immutable, then you get a lot of advantages: your rendering code can draw the current game state independently while the game update is computing the next game state. Immutability has some performance costs, but the concurrency advantages are huge if you can make it work. Both of my mini Clojure games (Ironclad and Alchemy) use this approach
You should probably try and store your game state in a single top-level var. I find this works better than splitting different parts of the game state over different vars. It also means that you don't really need ref-based transactions: an atom or agent will usually do the trick.
You may want to implement a queue of events that need to get processed sequentially by the game state update function. This is particularly important if you have multiple concurrent event sources (e.g. player actions, timer ticks, network events etc.)
Nowadays I would consider core/async to be a good choice, since
it scales very well when it comes to complex tasks that can be separated into activities that communicate using channels
avoids binding activity to a thread
here is the sketch
(require '[clojure.core.async :refer [go-loop]])
(go-loop []
(do
(do-something ...)
(Thread/sleep 1000)
(recur))))
This solution assumes you're writing Clojure on the JVM.
Something like this could work:
(import '(java.util TimerTask Timer))
(let [task (proxy [TimerTask] []
(run [] (println "Here we go!")))]
(. (new Timer) (schedule task (long 20))))

How to create a background music?

I need to run a background music in WP7 Silverlight application. I need it to keep playing when navigating between pages.
Also I don't want it to stop when another sound effect is played.
You can use a MediaElement to do that or use XNA SoundEffects but I have a better solution. Create a SilverXNA project for your app. You don't really need to use XNA but this project automatically creates some stuff which makes life easier. You can use this to build a Silverlight App with no problems.
After creating the project include your sound file in the project say "7am.mp3" and set it's build action to "Content".
Create a song in GamePage.xaml.cs:
Song music;
Now add this in OnNavigatedTo():
music = contentManager.Load<Song>("7am");
After this you can play this song as:
MediaPlayer.Play(music);
You may set the volume etc.
So, why this approach? Well, because according to technical certification guidelines you cannot interrupt a user if he is already listening to a song and SoundEffects class cannot be used for background music thus this method is the only way to get such flexibility.
You can use MediaPlayer.GameHasControl to see if user is playing music or not.
The solution was in referencing Microsoft.Xna.Framework then using the following function:
public static void PlaySound(string soundFile)
{
var stream = Application.GetResourceStream(new Uri(soundFile, UriKind.Relative)).Stream;
if (stream != null)
{
var effect = Microsoft.Xna.Framework.Audio.SoundEffect.FromStream(stream);
Microsoft.Xna.Framework.FrameworkDispatcher.Update();
effect.Play();
}
}
http://spacemigas.wordpress.com/2011/04/07/overcoming-windows-phone-7-mediaelement-limitations/

MediaElement is repeating clips automatically, and sometimes fails to play them

I have an app which plays a few short sound clips. To play them I simply set the source to the new clip path, which is a WMA I encoded with Expression Encoder using WP7 settings. It's not even worth sharing the code -- there's an event handler. In it, I set the ME.Source property to a new Uri. It's set to AutoPlay, so that's it! Here:
private void PlaySound(ItemViewModel sound) {
Model.CurrentSound = sound;
CurrentSound.Source = new Uri(sound.Path, UriKind.Relative);
}
private void Sounds_SelectionChanged(object sender, SelectionChangedEventArgs e) {
var list = ((ListBox) sender);
var item = (ItemViewModel) list.SelectedItem;
SelectItem(item);
}
Also I should point out that the sounds are all resources (build type = Resource). I need them to be because the app needs to discover them dynamically. The paths are all like this, "sounds/foo/bar/sound.wma". Sometimes there is a space in the path, it is url encoded with %20 (this is how the resource manager returns the path, I didn't do that).
The problem is many people, but not all, are saying that the sound auto-repeats. The sounds are very short, only a few seconds, so it's very annoying. I don't understand how this is happening, the MediaElement doesn't even have an auto repeat feature.
Perhaps related, but some have also complained that every now and then the sound does not play. They have to click it again. All I can think of is that there is something wrong with how the sounds are encoded, but they are WMA, and as I said, I encoded them using the 'playback in WP7' settings in expression encoder. How could it be that it works usually but not other times if that were the case, anyway?
I'm at a loss and my app is getting some bad reviews because of this behavior. Help!
"there's and event handler" but you don't say of what? It could be that event firing over and over or not at all in some cases. Potentially your code has a logical errors where you have failed to detach an existing handler and then added another. As usage progresses you end up with a single event being handled by multiple handlers.
Edit
The Selection changed event is notorious for firing more frequently than we'd like. I suggest you add some debounce code that makes record of the last item selected and how long ago. If the next selected item is the same as the last one and it was say less than a second ago then swallow the event without doing anything else.
It sounds like you might be trying to play Sound Effects - in which case you might be better off using the XNA SoundEffect mechanism
e.g. http://www.japf.fr/2010/08/sound-effect-in-wp7-sl-application/
SoundEffect only works for WAV files (PCM) - but I've used it in several apps and scripts including embedded content files and downloaded files (e.g. translation and ironruby scripts).
The XNA class works well within SL and allows multiple sound effects to be played at the same time.
The problem with repeating turned out to be needing to do this:
MediaPlayer.IsRepeating = false;
I think what happened was the user would be in another app that sets this to true, and upon opening my app that value was still true! That has to be a bug, it's totally unexpected. If you look at other sound-playing apps like soundboard apps, there are users complaining in the reviews about the very same thing.. "I wish it wouldn't repeat the sounds..."

Windows Phone 7: Media file plays multiple times before one finishes

My silverlight code:
var stream = TitleContainer.OpenStream("Giggle.wav");
var effect = SoundEffect.FromStream(stream);
FrameworkDispatcher.Update();
effect.Play();
The file, Giggle.wav plays multiple times. I expected the code would wait while the "Play" method executes.
Suggestions to make it play one instance at a time?
Thanks
How about DynamicSoundEffectInstance? Play your sound and when BufferNeeded event occurs - play next one. I am not sure but I think I saw another way how to play a sound synchronously. When I will find I will let you know.

Using Silverlight 2 for short audio caching

I'm attempting to use a large number of short sound samples in a game I'm creating in Silverlight 2. The samples are less than 2 seconds long.
I would prefer to load all the audio samples onto the canvas during the initualization. I have been adding the media element to the canvas and a generic list to manage it. So far, it appears to work.
When I play the sample the first time, it plays perfectly. If it has finished playing and I want to re-use the same element, it cuts off the first part of the sound. To play the sample again, I stop and play the media element.
Is there another method I should use the samples so that the audio is not clipped and good performance is obtained?
Also, it's probably a good idea to make sure that all of your audio samples are brought down to the client side initially. Depending on how you set it up, it's possible that the MediaElements are using their progressive download functionality to get the media files from the server. While there's nothing wrong with this per se (browser caching should be helping you out after the initial download), it does mean that you have to deal with the browser cache, and there are some potential issues there.
Possible steps to try:
Mark your audio files as "Content". This will get them balled up in the .xap.
Load your audio files into MemoryStreams (see Application.GetResourceStream method) and call MediaElement.SetSource().
HTH,
Erik
Some comments:
From MSDN:
Try to limit the number of MediaElement objects you have in your application at once. If you have over one hundred MediaElement objects in your application tree, regardless of whether they are playing concurrently or not, MediaFailed events may be raised. The way to work around this is to add MediaElement objects to the tree as they are needed and remove them when they are not.
You could try to seek to the start of the sample to reset the point currently being played before re-using it with:
mediaelement.Position = new TimeSpan();
See also MSDNs MediaElement.Position.
One techique you can use, although I'm not sure how well it will work in Silverlight, is create one large file with all of your samples joined together (probably with a half-second or so of silence between each). Figure out the timecode for each sample and seek the media element to that position and play. You'll only need as many media elements as simultaneous sounds you want to play.

Resources