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
Related
Here is the basic idea of my code:
private void CaptureCameraFrame()
{
Capture = new VideoCapture();
CameraModel.Instance.CameraViewMat = Capture.QueryFrame();
// do stuff with queried matrix here
if(noAbortCondition)
{
CaptureCameraFrame();
}
}
The method should run in a separate thread updating my GUI with the current image after processing.
Only Problem is, that I get two different kinds of error:
Attempt to read/write protected memory: This happens on the second runthrough
of the method.
I get an null-reference error using `CameraModel.Instance.CameraViewMat right after querying the frame.
The two issues seem to be connected, seems like QueryFrame() runs asynchronously from the rest of the code and isn't done when the program jumps to the next step.
Question is: How can I make sure, that querying the image from the camera is finished, and I can use the information in the matrix as well as start a new query?
In all the examples I have found this is done by using time, but I would like to start with a new frame as soon as processing on the last frame is done.
I haven't really done much in C# when it comes to threading, but what I understand in such cases one would use the asyncand awaitkeywords to make sure a method in an asynchronous method is finished. However I wasn't able to make a working implementation in this case.
You are creating VideoCapture class instance repeatedly and even not disposing of it. Create your VideoCapture instance only once and use them for your task. At the end dispose it.
public YourConstructor()
{
Capture = new VideoCapture();
}
private void CaptureCameraFrame()
{
CameraModel.Instance.CameraViewMat = Capture.QueryFrame();
// do stuff with queried matrix here
if(noAbortCondition)
{
CaptureCameraFrame();
}
}
Hopefully, it will work for you!
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.
I am creating an audio recorder control, with playback functionality.
I use the media element to play the recorded audio like this:
using (var storage = System.IO.IsolatedStorage.IsolatedStorageFile.GetUserStoreForApplication())
{
using (System.IO.Stream stream = new System.IO.IsolatedStorage.IsolatedStorageFileStream(filePath, System.IO.FileMode.Open, storage))
{
player.SetSource(stream);
}
}
The problem i am facing is that when I use media element to play the recorded audio. The Stream is locked to the media element. I cannot overwrite the file or even play it again as the SetSource() method throws an exception.
Is there a way to force the media element to release the stream?
Based on #Sheridan answer this it what I came up with that works.
Whenever MediaElement is stopped using Stop() function set the Source Property to null like this:
ResetMediaElement()
{
mediaElement.Stop();
mediaElement.Source = null;
}
This will close the stream attached to the media element, so that the related resource can be used somewhere else.
If you use MediaElement, make sure you don't get bitten by this one:
http://msdn.microsoft.com/en-us/library/cc626563(v=vs.95).aspx
ArgumentNullException - The mediaStreamSource is null.
...
After calling this method, MediaElement.Source returns null. If this
is called and MediaElement.Source is set, the last operation wins.
If a MediaElement is removed from the UI tree while is has an opened
MediaStreamSource, subsequent calls to SetSource may be ignored. To
ensure featureSetSource calls will work, set the Source property to
null before detaching the MediaElement from the UI tree.
naturally one would expect, if they only use SetSource(somestream) to use SetSource(null) to release the resources. Nope, they thought "better", you have to use Source=null instead to release resources and SetSource(null) throws ArgumentNullException
that is what I call a design bug (breaks the rule of "least expected" behavior and causes bugs that bite you at runtime only [unless somebody has made a static analysis rule to catch such a thing - would need metadata of course that some argument can't be null, like in Code Contracts])
I managed to introduce this bug while refactoring some code in ClipFlair Studio's AudioRecorder control the other day :-(
Note that you can’t use at MediaElement something like Source = stream to open a Stream, since that is a Uri property (not an Object property to also accept Stream) and you have to use SetSource(stream) instead, so you’d also expect to be able to use SetSource(null) to release the resources.
Update: Fixed this in AudioRecorderView class (uses MVVM pattern) of AudioRecorderControl, at Audio property’s "set" accessor it needed the following null-guarding pattern:
if (mediaStreamSource != null)
player.SetSource(mediaStreamSource);
//must set the source once, not every time we play the same audio,
//else with Mp3MediaSource it will throw DRM error
else
player.Source = null;
mediaElement.Stop();
mediaElement.ClearValue(MediaElement.SourceProperty);
I had a similar problem with displaying images. In a control with an image, I would get a 'File is in use' error whenever the user tried to update the image. The solution was to set the BitmapImage.CacheOption property to BitmapCacheOption.OnLoad:
MSDN says Set the CacheOption to BitmapCacheOption.OnLoad if you wish to close a stream used to create the BitmapImage. The default OnDemand cache option retains access to the stream until the image is needed, and cleanup is handled by the garbage collector.
After searching for a similar property that you could use for your MediaElement, it turns out that there isn't one. However, according to an answer on the chacheoption for mediaelement post from MSDN, there is a (long winded) way to achieve this... from the relevant answer:
I am not sure if your MediaElement is in an UserControl or not. but
whatever the case you can set the UserControl or Control to
IsEnabled=false, which in turn will trigger the Event Handler
IsEnabledChanged. In it place the necessary code to stop the
MediaElement from playback ME.Stop(), then call ME.Clear() and
ME.Source = null. After that you should find no problems to delete the
source file.
ME.Source = new Uri(MediaFilePath);
ME.Play();
...
private void DeleteButton_Click(object sender, RoutedEventArgs e)
{
ME.IsEnabled = false; // This will call the Event Handler IsEnabledChanged
System.IO.File.Delete(MediaFilePath);
// Now after the player was stopped and cleared and source set to null, it
// won't object to deleting the file
}
private void ME_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
ME.Stop();
ME.Clear();
ME.Source = null;
}
I hope that this helps.
I am creating a game for windows in xna using Visual C# Express. In the game, there are six SoundEffect objects which regularly have their Play() methods called. The problem is that sometimes when the game is closed it crashes. It appears to happen whenever the window is closed while a soundeffect is playing. This is the message which pops up in Visual C#:
AccessViolationException was unhandled
Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
There isn't any source available in visual studio to debug and when the "get general help for this exception" is clicked, a blank page pops up..
The code used looks a lot like the MSDN example. This looks like a problem that exists somewhere in the underlying framework somewhere, not my code. But of course I don't know for sure. This has happened many times.
http://msdn.microsoft.com/en-us/library/bb195053.aspx
Here are the complete exception details:
System.AccessViolationException was unhandled
Message=Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Source=Microsoft.Xna.Framework
StackTrace:
at Microsoft.Xna.Framework.Audio.AudioCallbackDispatcher.IsEventRegistered(EventType type)
at Microsoft.Xna.Framework.Audio.AudioCallbackDispatcher.UnregisterEvent(EventType type)
at Microsoft.Xna.Framework.Audio.KernelMicrophone.ShutdownCaptureEngine()
at Microsoft.Xna.Framework.Audio.MicrophoneUnsafeNativeMethods.ShutdownCaptureEngine()
at Microsoft.Xna.Framework.Audio.AudioRendererShutdownHandler.AppExitingEventHandler(Object sender, EventArgs args)
InnerException:
(I also have music playing via MediaPlayer, but I don't think it's related.)
EDIT: I seem to have found something which works, but it's kind of hackish and really shouldn't be necessary. I'm still open to any more elegant solutions.
Call this line in Game1.UnloadContent(). It will make sure (if your sound effects are all shorter than 3 seconds) that no sound is playing when the program actually closes.
System.Threading.Thread.Sleep(3000);
Make the SoundEffect object a class member and call the SoundEffect's Dispose() method on class deconstruction:
class MyClass
{
~MyClass()
{
effect.Dispose();
}
SoundEffect effect;
}
This should let the SoundEffect object clean itself up when you close the game. You can read about objects that are Disposable here: http://msdn.microsoft.com/en-us/library/system.idisposable.aspx
Can you make MyClass implement IDisposable and dispose of the SoundEffect in that method?
I think it's pretty safe to say that this is a bug in the framework. Because it's in the audio code, perhaps the framework is not handling something it's getting from a driver correctly. It's hard to say for sure.
Suffice to say that an AccessViolationException coming out of the framework is not "normal". It's almost certainly not your fault.
The function IsEventRegistered that the exception occurs in is an unsafe function. So it's likely that function is doing exactly what the exception says: it is accessing an invalid memory address.
The exception is coming from the shutdown code for audio capture (microphone), so are you doing anything with the microphone in your code? You could possibly experiment with using/not using the microphone and see what happens.
Also: does this happen when you run without the debugger attached? (Ctrl+F5)
As for fixing the problem: Your solution is not a bad work-around.
If you cannot afford to wait the three seconds, and you want to get your hands dirty and write some very questionable (semi-unportable, not-necessaraly-forward-compatible) code: You could use reflection to access the private properties of the audio system. Find the list of SoundEffectInstance objects that are created internally whenever you call SoundEffect.Play, and then stop those instances before you shutdown.
Or you could do effectively the same thing by never calling Play, but instead calling CreateInstance and managing fire-and-forget sound effects on your own. The downside is that this requires writing an awful lot of code!
I had the same problem and I did nulls for my sound collections in class finalizer(destructor). Works for me.
public class Audio
{
private ContentManager content;
public List<SoundEffectInstance> SoundInstance { get; private set; }
public AudioEmitter Emitter { get; set; }
public AudioListener Listener { get; set; }
public List<SoundEffect> Sound { get; set; }
public Audio(ContentManager content)
{
this.content = content;
Emitter = new AudioEmitter();
Listener = new AudioListener();
Sound = new List<SoundEffect>();
SoundInstance = new List<SoundEffectInstance>();
}
//set to null your sound instances and effects :D
~Audio()
{
Sound = null;
SoundInstance = null;
}
...
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();
}