I'm making a drum machine. From what I've read, it looks like the XNA SoundEffect class runs based on a timer, which causes a noticeable lag, and stops the rhythm being smooth.
I tried to use MediaElement, 'til I found out you cannot play multiple sounds at the same time.
Are there any workarounds for this? The sounds are handled by a timer, and need to play instantly.
I've done some in-game use of the XNA SoundEffect class and not seen any lag when responding to user events - e.g. button presses - especially when the sound effect is pre-loaded from resources.
The XNA class is designed to be used for sound effects - so it should be ideal for a single drum machine hit.
If you then see problems with timing on IsLooping, then I guess you'll have to implement your own timer to trigger new instances - but my advice would be to try it first.
Hope that helps
I've been using some sound in my app and I used the code from the example given on the msdn code samples website: http://msdn.microsoft.com/en-us/library/ff431744(v=vs.92).aspx
It looks like they are updating the timer every 50ms. Also note that the SoundEffect variables (coyoteSound and birdSound) are private data members where they only load once. The event handler on the button clicks simply call SoundEffect.play().
public MainPage()
{
InitializeComponent();
LoadSound("Resources/NightAmbientCreatureOneShot_01.wav", out coyoteSound);
LoadSound("Resources/AfternoonAmbientBirdOneShot_09.wav", out birdSound);
LoadSoundInstance("Resources/NightAmbienceSimple_01.wav", out ambienceSound, out ambienceInstance);
// Set the volume a little lower than full so it becomes the background.
ambienceInstance.Volume = 0.8f;
// Turn on looping so it runs continually in the background.
ambienceInstance.IsLooped = true;
// Timer to simulate the XNA game loop (SoundEffect classes are from the XNA Framework)
DispatcherTimer XnaDispatchTimer = new DispatcherTimer();
XnaDispatchTimer.Interval = TimeSpan.FromMilliseconds(50);
// Call FrameworkDispatcher.Update to update the XNA Framework internals.
XnaDispatchTimer.Tick += delegate { try { FrameworkDispatcher.Update(); } catch { } };
// Start the DispatchTimer running.
XnaDispatchTimer.Start();
}
Related
This question already has answers here:
How to use System.Media.SoundPlayer to asynchronously play a sound file?
(2 answers)
Closed 5 years ago.
I've been trying to get this button to do what I want for a little now. I want it to play a sound when I press it, which is what I managed to do. However, its like the application freezes every time you press the button, giving the sound all of its attention, etc. So basically my goal is to make the button play a sound without making the UI have to stop and allow it to play, before moving on. I also would like to know if there is a way to make a button play sound when pressed, but when pressed again the current sound is stopped and plays again, to prevent it from playing "X" amount of clicks you clicked the button, etc.
Here is my code:
public static void ButtonSound()
{
SoundPlayer _sound = new SoundPlayer();
try
{
_sound.Stop();
_sound.SoundLocation = path + "ButtonTap.wav";
_sound.Load();
_sound.PlaySync();
}
catch
{
}
finally
{
_sound.Dispose();
}
}
And Button code:
private void Button()
{
SoundPlayers.ButtonSound();
}
Note, I have my SoundPlayer in another class, and I am using DelegateCommands to reference my Button() method, etc. I am also using .wav files. Also, is there a more efficient way to achieve that task I am trying to accomplish? If you need anything else, just ask.
Thanks!
Your UI is freezing because that is what you are asking for when you call _sound.PlaySync().
Looking at the SoundPlayer documentation, you could use the Play() method:
Plays the .wav file using a new thread, and loads the .wav file first
if it has not been loaded.
Using this method should also solve the problem of playing the sound repeatedly, since you will no longer be queuing your calls.
Also, what you did there with Try-Finally-Dispose can be simplified with using, so your code would look like this:
public static void ButtonSound()
{
using (var _sound = new SoundPlayer())
{
_sound.SoundLocation = path + "ButtonTap.wav";
_sound.Play();
}
}
Note that your _sound.Stop() doesn't make sense, since you are calling it on a new object, but just calling Play() on a new object will make the old sound stop and then play the new one.
Also, the doc says that Play() loads the file if it has not been loaded, that is why I skipped the _sound.Load() call.
Before I start, I'd like to appologize for any... idiocy... that I may show when asking this question, I'm trying to learn C# after coming from Java, and just wanted to jump right into it!
I'm working on a project that is designed to take commands through the console, such as "play batman begins" and it'll start playing the movie Batman Begins. It also takes commands for music, etc. With this setup, my goal is to have it voice controlled, so I'm not really concerned with using a GUI instead of the console. When I have the program play a movie, it loads up a GUI window with no border, no content, and the constructor that it uses is:
public MainWindow(MediaPlayer player)
{
InitializeComponent();
VideoDrawing drawing = new VideoDrawing { Rect = new Rect(0, 0, 800, 600), Player = player };
DrawingBrush brush = new DrawingBrush(drawing);
Background = brush;
}
The MediaPlayer is controlled from the main function (for now). My code to load the video and run it is:
MediaPlayer mp = new MediaPlayer();
mp.Open(new Uri("C:\\test.mp4", UriKind.RelativeOrAbsolute));
VideoDrawing vidDrawing = new VideoDrawing();
vidDrawing.Rect = new Rect(0, 0, 100, 100);
vidDrawing.Player = mp;
DrawingBrush DBrush = new DrawingBrush(vidDrawing);
videoPanel = new MainWindow(mp); // GUI panel to play the video on, constructor is listed above
play();
new System.Windows.Application().Run(videoPanel);
As I'm new to C# and all, the way I got the GUI to work with this is by starting a new WPF project, creating the GUI and writing the code, then copy paste the xaml and cs files into my project (cause I'm a noob, I'm sorry). MAYBE this is causing the problem.
This code works (mostly) fine. When I run my program, it loads the video file, opens the Window, and plays the video on the screen while playing the sound too. However, when it starts the video, the GUI "hangs" and doesnt accept any input's OR outputs, but it's not frozen as the cursor is still flashing. I'm not sure why this is.
I've tried threading almost anything I can think of, but I get errors with that. I've tried localizing the loading to the GUI window itself, however it still hangs the console. I've been searching online for all sorts of things for the past few days and cant find a solution, so I turned here!
My program has a lot more classes and stuff going on, so I had to throw all this stuff together, and double check, so if I'm missing something or made a stupid please let me know and I can fix it. As I'm still kinda new to C# (but not new to programming) I may have missed something in my question details as well.
I'm wondering if the solution is to make it ALL GUI based, instead of hybrid console and GUI? Because of the information I've found online it looks like there can be some annoying... discrepancies... between the two types of threads?
Anyway, any help would be great, I've spent the past 3 days trying to debug this and haven't made any progress. If it helps, there's a link to the repo here! Thanks :)
EDIT: I made some changes while waiting for a response, primarily changing the way it draws to the GUI. Originally I had it painting to the background, but now have made it handle through a MediaElement. This is the whole class for my window now:
public partial class MainWindow : Window
{
public MainWindow(string dir)
{
InitializeComponent();
video.Source = new Uri(dir); //video is the name of my MediaElement
}
public void pause(){
video.Pause();
}
public void resume()
{
video.Play();
}
public void stop()
{
video.Stop();
this.Close();
}
public void volume(int i)
{
video.Volume = i;
}
}
This did NOT fix the console Hang, however this made everything much more centralized so as to make debugging easier. Hope this may help!
Consider converting this to a WPF-application, it will make things easier.
Anyway, you can still work with GUI without locking console, but you must execute GUI-related stuff on a separate dedicated STA thread. Since you are using WPF, this helper should be useful (this code is not production-quality, but works):
static class UIThread
{
private static Dispatcher _dispatcher;
public static void Start()
{
using(var wh = new ManualResetEvent(false))
{
var thread = new Thread(ThreadProc)
{
IsBackground = true,
};
thread.SetApartmentState(ApartmentState.STA);
thread.Start(wh);
wh.WaitOne();
}
}
private static void ThreadProc(object arg)
{
var wh = (EventWaitHandle)arg;
_dispatcher = Dispatcher.CurrentDispatcher;
wh.Set();
Dispatcher.Run();
}
public static Dispatcher Dispatcher
{
get { return _dispatcher; }
}
}
This helper provides you with a reference to a Dispatcher object, which is used to execute methods on UI thread.
All communication with UI thread should be done through Dispatcher.Invoke() or Dispatcher.BeginInvoke() methods. Note that since we now have several threads, MediaPlayer objects must be created on the UI thread. You can still hold it's reference on any thread you want, but any method calls to MediaPlayer object must go through Dispatcher.
Things to change:
add a UIThread.Start(); call before any attempts to use Dispatcher. Beginning of Main() method is a good place to do this.
MediaPlayer objects should be created like this: mediaPlayer = UIThread.Dispatcher.Invoke(() => new Media());
any UI-related code should go to Dispatcher.Invoke() or Dispatcher.BeginInvoke(): UIThread.Dispatcher.BeginInvoke(() => playVideo(#"C:\video.avi"));
Update
Also change new System.Windows.Application().Run(videoPanel); to simple videoPanel.Show(). Application.Run() blocks until the window is closed.
Here is the setup I am rolling at the moment. Given this, how can I tell when the _BGMusic SoundEfect is over? I am running a game loop that cycles a few times a second and I ultimately want to loop this song.
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
SoundEffect _BGMUSIC;
public Page1() {
...
LoadSound("sfx/piano.wav", out _BGMUSIC);
...
}
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);
FrameworkDispatcher.Update();
} catch (NullReferenceException) {
// Display an error message
MessageBox.Show("Couldn't load sound " + SoundFilePath);
}
}
From this code it looks like you have just stored the sound in Sound but you don't show where you implement the Sound.Play() method. While there isn't a Sound.IsPlaying boolean which would probably solve your problem, there is a Sound.Duration property which you may use to solve your problem, especially if you couple that with a Timer (which can be used in tandem to set off a flag to show whether or not the sound is playing.
Also something I have never used but just found is the Sound.IsDisposed property. I would definitely look into this as well because it may be exactly for what you are looking.
Alright so the answer to this question is actually very simple and outlined in Microsoft's MSDN page very nicely (for once).
To implement it with what I have up above currently you need to do the following.
Create a global SoundEffectInstance
SoundEffectInstance _BGMUSICINSTANCE;
In my example I initialize the SoundEffect in my main method so underneath it I want to initialize the SoundEffectInstance.
_BGMUSICINSTANCE = _BGMUSIC.CreateInstance();
Now that the instance is loaded and ready we can set its loop property to true. You can do this also in the main method or wherever you want. It's a global
_BGMUSICINSTANCE.IsLooped = true;
Finally play the song
_BGMUSICINSTANCE.Play();
Reference page
http://msdn.microsoft.com/en-us/library/dd940203(v=xnagamestudio.31).aspx
I'm trying to raise an event at a given time in my windows store app. Now I've done this in desktop apps countless times, and I've used System.Threading.Timer in the past and it has worked well, but that class is not available to windows store apps.
I have looked in the documentation and found a class called DispatchTimer and although it appears to be what I'm after, correct me if I'm wrong but the docs are lacking. But luckily it's pretty easy to use.
So I tried the DispatchTimer, but after using it, I'm not even sure this is what I should be using.
How can I watch for any given time and raise an event when that time is up (in a windows store app)? And do you know of any resources that do this in a metro app?
Use DispatcherTimer like this:
var timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(10) };
timer.Tick += OnTimerTick;
timer.Start();
private void OnTimerTick(object sender, object args)
{
// Do something with pickup here...
}
This will create a timer with intervals of 10 seconds.
The DispatcherTimer is the way to go. Notice that if you want your app to run in background you must declare that on the app manifest or use Background agents.
Hi I am making a windows phone app. I used some sound tracks using Soundeffect class but I want to stop the music of that track on a button clicking event (it has a play method but does not have a stop method) so how can I achieve this ? The language used is C#
The Play method provided by SoundEffect is just a convenience method for doing fire-and-forget sounds. You need to create a SoundEffectInstance (MSDN) if you want to do anything more fancy.
// At load time:
SoundEffect mySoundEffect = Content.Load<SoundEffect>("mySound");
SoundEffectInstance mySoundEffectInstance = mySoundEffect.CreateInstance();
// During your game:
mySoundEffectInstance.Play();
mySoundEffectInstance.Stop();
// When you're done with it:
mySoundEffectInstance.Dispose();
(Note that you do not Dispose() of mySoundEffect, as its lifetime is managed by the ContentManager that loaded it.)
I think the Soundeffect class should be used for short sound effects you would not want to pause because they are short.
Are you using XNA ? If yes, have a look at the MediaPlayer class.
If not, try using the BackgroundAudioPlayer class.