Music suddenly stops playing in C# Windows Form application - c#

In my app there should normally be 2 sounds that overlap (a song and some short sounds). It works fine until from time to time the song suddenly stops playing. Do you know how I could solve this issue?
Here are the functions that I used for adding the songs and the sounds:
private void musical()
{
var p1 = new System.Windows.Media.MediaPlayer();
p1.Open(new System.Uri(#"J:\penalty\penalty\penalty\bin\Debug\Avicii - The Nights (Lyrics HD).wav"));
p1.Play();
}
private void happy()
{
System.Threading.Thread.Sleep(500);
var p2 = new System.Windows.Media.MediaPlayer();
p2.Open(new System.Uri(#"J:\penalty\penalty\penalty\bin\Debug\happy.wav"));
p2.Play();
}
private void sad()
{
System.Threading.Thread.Sleep(500);
var p2 = new System.Windows.Media.MediaPlayer();
p2.Open(new System.Uri(#"J:\penalty\penalty\penalty\bin\Debug\sad.wav"));
p2.Play();
}

If you don't store a reference to the MediaPlayers as field but only in local variables they are likely going to be gargabe collected. This might happen delayed as MediaPlayer uses unmanaged resources that would require a Dispose before being freed. To fix your problem consider storing a reference to the MediaPlayers in a field.
private System.Windows.Media.MediaPlayer _music;
private System.Windows.Media.MediaPlayer _happy;
private System.Windows.Media.MediaPlayer _sad;
and then adjust your methods to use the field instead.
private void musical()
{
_music = new System.Windows.Media.MediaPlayer();
_music.Open(new System.Uri(#"J:\penalty\penalty\penalty\bin\Debug\Avicii - The Nights (Lyrics HD).wav"));
_music.Play();
}
If you would like to repeat the audio (which does not work very well) you can subscribe the MediaEnded event in order set the position back to the beginning and start playing again.

Related

Moving Between One Form to Another - C#

I am currently creating a video game and coding the movement in a house between upstairs and downstairs. I'm using PictureBoxes in combination with an IntersectWith event to transition between forms.
Transition Code to go Upstairs:
if(picPlayer.Bounds.IntersectsWith(picUpstairsTransition.Bounds))
{
MapFrmHouseUpstairs upstairs = new MapFrmHouseUpstairs();
this.Hide();
upstairs.ShowDialog();
}
Transition Code to Go Back Downstairs:
if(picPlayer.Bounds.IntersectsWith(picGoDownstairs.Bounds))
{
MapFrmHouse goDownstairs = new MapFrmHouse();
this.Hide();
goDownstairs.ShowDialog();
picPlayer.Location = new Point(497, 103);
}
The issue I have is that when the player enters the house, he starts at the front. When he tries to come back from upstairs, the character is moved back to the front instead of the base of the stairs. Is there anyway I could create a method within MapFrmHouse such as:
public void fromDownstairs{picPlayer.Location = new Point(x,y);}
And call it when going downstairs?
First of all you'd better use a game engine to design games like Unity which is much easier and more fun. This might be a learning task for you though which I don't blame :)
You can send information between forms in Windows Forms in many ways, two of which seems to fulfill your needs:
Using a higher level modifier for objects
Initializing values in constructors
To do the first you set the modifier property of the picture box called picPlayer in your MapFrmHouse class from private to public then you can do exactly what you mentioned:
if(picPlayer.Bounds.IntersectsWith(picGoDownstairs.Bounds))
{
MapFrmHouse goDownstairs = new MapFrmHouse()
{
picPlayer.Location = new Point(x,y);
};
this.Hide();
goDownstairs.ShowDialog();
}
For the second method you should create an overload constructor in your MapFrmHouse and accept a Point value in it and then set it your value like this:
public MapFrmHouse(Point p)
{
InitializeComponent();
picPlayer.Location = p;
}
And then use it in your code like this:
if(picPlayer.Bounds.IntersectsWith(picGoDownstairs.Bounds))
{
MapFrmHouse goDownstairs = new MapFrmHouse(new Point(x,y));
this.Hide();
goDownstairs.ShowDialog();
}
I hope this helps :)

Threading issue with MediaPlayer C#

I am creating an app that has an 9x9 multidimensional array full of custom objects, and when a button is pressed a sound specific to every single object needs to be played.
I run this method to load the sound, runs with no known problems:
public void setSoundToPlay()
{
OpenFileDialog openFileDiag = new OpenFileDialog();
if ((bool)openFileDiag.ShowDialog())
{
audio = new MediaPlayer();
audio.Open(new System.Uri(openFileDiag.FileName));
}
}
but when I activate another method to play sound:
public void buttonActivated()
{
audio.Play();
}
I get a System.InvalidOperationException:{"The calling thread cannot access this object because a different thread owns it."}
The object running the mediaplayer object is nested within another object, is that the problem. I tried understanding threading but have made no headway.
I also need to, in some cases, need to have all the sounds be able to play at once. Is this the best object for the job?
Use the Dispatcher property associated with the media player element, like this
public void buttonActivated()
{
audio.Dispatcher.Invoke(() =>
{
audio.Play();
});
}
To access devices like this from other methods use
Application.Current.Dispatcher.BeginInvoke(new Action(() => objectName);

Windows 8 xaudio2 playing wav file in multitouch app

I am learning how to work with xAudio2. Made a simple application Windows 8 in Visual Studio 2012 Express For Windows 8.
Simple xAudio2 player class:
public class SoundEffect
{
readonly XAudio2 _xaudio;
readonly WaveFormat _waveFormat;
readonly AudioBuffer _buffer;
readonly SoundStream _soundstream;
SourceVoice sourceVoice;
public SoundEffect(string soundFxPath)
{
_xaudio = new XAudio2();
var masteringsound = new MasteringVoice(_xaudio);
var nativefilestream = new NativeFileStream(
soundFxPath,
NativeFileMode.Open,
NativeFileAccess.Read,
NativeFileShare.Read);
_soundstream = new SoundStream(nativefilestream);
_waveFormat = _soundstream.Format;
_buffer = new AudioBuffer
{
Stream = _soundstream.ToDataStream(),
AudioBytes = (int)_soundstream.Length,
Flags = BufferFlags.EndOfStream
};
//sourceVoice = null;
}
public void Play()
{
sourceVoice = new SourceVoice(_xaudio, _waveFormat, true);
if (sourceVoice != null)
{
sourceVoice.FlushSourceBuffers();
sourceVoice.SubmitSourceBuffer(_buffer, _soundstream.DecodedPacketsInfo);
sourceVoice.Start();
}
}
public void Stop()
{
sourceVoice.Stop();
}
}
And Xaml:
<Border Background="Gray" MinHeight="150" MinWidth="150" Margin="10,10,0,0" x:Name="A" PointerPressed="btnAPointerPressed" PointerReleased="btnAPointerReleased" />
and:
private SoundEffect shotEffect = new SoundEffect(#"sounds\mywav.wav");
private void btnAPointerPressed(object sender, PointerRoutedEventArgs e)
{
bool _hasCapture = ((Border)sender).CapturePointer(e.Pointer);
shotEffect.Play();
}
private void btnAPointerReleased(object sender, PointerRoutedEventArgs e)
{
((Border)sender).ReleasePointerCapture(e.Pointer);
shotEffect.Stop();
}
Tested in Windows 8 Simulator.
If I press one finger, then everything is fine.
When I click on the button - the sound plays when I let go of your finger - the sound stops.
If I click with two fingers and let go of both fingers, the sound continues to play. And the result is aliasing.
Called two events: btnAPointerPressed and two events: btnAPointerReleased but the sound continues to play. As if the audio stream freezes and continues to play. As if the audio stream freezes and continues to play.
I want to understand the problem haudio2? or I do not properly done something?
When you call Play() again - the previous SourceVoice gets replaced with a new one in your SoundEffect, but you never stop the old one. You should create a new SourceVoice with each touch, but keep them all associated with the pointer IDs so that we can stop each of them when the associated pointers are released.

MediaPlayer class listening for NaturalDuration.HasTimeSpan change

I am writing a custom audio player in c# using the MediaPlayer class. I have implemented a scroll bar so the user can seek through a track and this is where I am having the problem.
WHen the user selects an audio track (loaded from an xml playlist) the app calculates the length in seconds of the track and sets this as the max value for the scroll bar. This all works fine except the NaturalDuration.TimeSpan property sometimes returns 0 rather than the amount. I have proved this by adding a loop that exits when NaturalDuration.HasTimeSpan is true then returns the NaturalDuration.TimeSpan value.
My question is how can I just get the NaturalDuration.TimeSpan when the NaturalDuration.HasTimeSpan is changed to true?
The correct way to do this is to handle the MediaPlayer.MediaOpened event:
mediaPlayer = new MediaPlayer();
mediaPlayer.MediaOpened += MediaPlayer_MediaOpened;
mediaPlayer.Open(new Uri(mediaFilePath, UriKind.Absolute));
...
private void MediaPlayer_MediaOpened(object sender, EventArgs e)
{
if (mediaPlayer.NaturalDuration.HasTimeSpan)
{
SliderMaximum = mediaPlayer.NaturalDuration.TimeSpan.TotalSeconds;
mediaPlayer.Play();
}
}

MouseMove performance slow using GetPosition

I have a Canvas control with various elements on, in this particular function I am allowing a user to drag the end point of a line around the canvas. In the MouseMove function I call e.GetPosition().
The function is, according to the VS performance analyzer, close to 30% of total CPU for the app when constantly moving around. Its pretty slow. What can I do to increase this performance?
CurrentPoint = e.GetPosition(PointsCanvas);
I've faced the same problem while using MouseMove on windows phone 8. It seems that while dragging , events (containing the coordinates you need ) are raised at regular time interval ( depending on what you do in the implementation in your listeners, every 20 ms for example). So what I did was to populate a Queue with my coordinates and create a Thread that consume that Queue by enqueue the first element and do the logic I want. Like that the logic is not done serially because it's another thread who does the job.
I don't know if I'm enough clear so please take a look to the code below :
//Class used to store e.getPosition(UIElement).X/Y
public class mouseInformation
{
public int x { get; set; }
public int y { get; set; }
public mouseInformation(int x, int y, String functionName)
{
this.x = x;
this.y = y;
}
}
private readonly Queue<mouseInformation> queueOfEvent = new Queue<mouseInformation>();
//MouseMove listener
private void wpCanvas_MouseDragged(object sender, System.Windows.Input.MouseEventArgs e)
{
//Instead of "wpCanvas" put the name of your UIElement (here your canvas name)
mouseInformation mouseDragged = new mouseInformation((int)e.GetPosition(wpCanvas).X, (int)e.GetPosition(wpCanvas).Y);
EnqueueMouseEvent(mouseDragged);
}
//Allow you to add a MouseInformation object in your Queue
public void EnqueueMouseEvent(mouseInformation mi)
{
lock (queueOfEvent)
{
queueOfEvent.Enqueue(mi);
Monitor.PulseAll(queueOfEvent);
}
}
//Logic that your consumer thread will do
void Consume()
{
while (true)
{
mouseInformation MI;
lock (queueOfEvent)
{
while (queueOfEvent.Count == 0) Monitor.Wait(queueOfEvent);
MI = queueOfEvent.Dequeue();
}
// DO YOUR LOGIC HERE
// i.e DoSomething(MI.x, MI.y)
}
}
And don't forget to create the thread in your Main() or in MainPage_Loaded(object sender, RoutedEventArgs e) method if you are Windows phone user.
System.Threading.ThreadStart WatchQueue = new System.Threading.ThreadStart(Consume);
System.Threading.Thread RunWatchQueue = new System.Threading.Thread(WatchQueue);
RunWatchQueue.Name = "Events thread";
RunWatchQueue.Start();
To be simple less you do in your MouseMove listener, more speed it will be.
You can aswell do the logic asynchronously or even use Bresenham algorithm to simulate more events.
Hope it helps.
Are you using any effects such as dropshaddow etc?
I recently had the situation where e.GetPosition() was also using 30% of the app's cpu resources, which doesn't make any sense right?
I turns out that up the visual tree there was a control applying a dropshaddow effect and that was what was slowing everything down so much...

Categories

Resources