playing and stopping audio from two different buttons - c#

I'm running this code for pausing the song but it obliviously doesn't work.
I can't access the variables of the first button from the second one, so I can't pause the song.
How do you think I could do that?
I'm using the naudio library cause I wanted to put the audio file as resource.
private void button3_Click(object sender, EventArgs e)
{
MemoryStream mp3file = new MemoryStream(Properties.Resources.musica1);
Mp3FileReader mp3reader = new Mp3FileReader(mp3file);
var waveOut = new WaveOut();
waveOut.Init(mp3reader);
waveOut.Play();
if (pausa)
{
waveOut.Pause();
}
}
private void button2_Click(object sender, EventArgs e)
{
pausa = true;
}

You will need to restructure your code. The problem is that in your button3_Click method, you are loading and playing your MP3, but then the function immediately terminates. The if statement won't be continuously checked, which is what I think you assume will happen. Therefore, clicking button2 will simply change the state of pausa but this doesn't affect anything.
One way would be to make all the variables (mp3file, mp3reader, and waveOut) declared at the class level, then put the rest of the code inside button3_Click into, say, your form's Load event handler.
// These variables are declared at the class level
MemoryStream mp3file;
Mp3FileReader mp3reader;
WaveOut waveOut;
...
private void Form1_Load(object sender, EventArgs e)
{
mp3file = new MemoryStream(Properties.Resources.musica1);
mp3reader = new Mp3FileReader(mp3file);
waveOut = new WaveOut();
waveOut.Init(mp3reader);
}
Now, your buttonX_Click functions can look like this (assuming button3 is your Play button and button2 is your Pause button):
private void button3_Click(object sender, EventArgs e)
{
waveOut.Play();
}
private void button2_Click(object sender, EventArgs e)
{
waveOut.Pause();
}
Because waveOut is declared at the class level, both buttons have access to it, and can therefore play and pause at will. You don't need pausa anymore, unless of course you need to know the playing state elsewhere in the program.

Related

Play next file automatically using MediaPlayer Control(AxWindowsMediaPlayer)

When changing AxWindowsMediaPlayer URL in PlayStateChange Event, it doesn't start playing automatically, just changes to "Ready" state.
I have an "AxWindowsMediaPlayer" Control in my C# WinForms program. when I normally change the URL property of WindowsMediaPlayer1, it works fine and plays new mp3 file automatically.
When the song ended WindowsMediaPlayer1 State changes to Stopped and I Want next URL automatically start Playing.
I used PlayStatChange event, so when player state is Stopped, URL Will change, but Not playing automatically!
The player goes to Ready State until I press the play button on the WindowsMediaPlayer1.
Here is the Code:
private void Form1_Load(object sender, EventArgs e)
{
WindowsMediaPlayer1.URL = "6.mp3"; //Works fine
}
private void button1_Click(object sender, EventArgs e)
{
WindowsMediaPlayer1.URL = "4.mp3"; //Works fine. It changes the music.
}
private void WindowsMediaPlayer1_PlayStateChange(object sender,
AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
{
if (e.newState == 1) //1 is for "Stopped" State
WindowsMediaPlayer1.URL = "5.mp3";
// Here is the problem.
// URL Will change but player goes to "Ready" State
// But not in "playing" until I press the play button in control.
}
Any help would be appreciated.
As mentioned in media player documentations, you should not set the Url from event handler code. Instead you can play next file this way:
private void axWindowsMediaPlayer1_PlayStateChange(object sender,
AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
{
if (e.newState == 1)
{
this.BeginInvoke(new Action(() => {
this.axWindowsMediaPlayer1.URL = #"address of nextfile";
}));
}
}
Also as another option you can consider using a playlist.
I found this note on msdn about player.URL:
"Do not call this method from event handler code. Calling URL from an event handler may yield unexpected results."
so I tried another way to solve it and its worked.
added a timer and a bool varible to check if WindowsMediaPlayer1 is "Stopped"
Here is the solution:
public partial class Form1 : Form
{
bool nextURL = false;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
WindowsMediaPlayer1.URL = "5.mp3";
}
private void WindowsMediaPlayer1_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
{
if (e.newState == 1) // 1 is consider for "Stopped" State
{
nextURL = true; // if the song ended "nextURL" flag sets to true
}
}
private void timer1_Tick(object sender, EventArgs e)
{
if (nextURL)
{
WindowsMediaPlayer1.URL = "6.mp3";
nextURL = false;
}
}

I want to use BackgroundWorker to speed up my graphical appearances

I am writing a Kiosk-type program for a media center PC. I have some pictureBoxes as my buttons, and would like a label or another pictureBox (acting as a label) to be visible/not visible and be triggered by a MouseEnter and MouseLeave event.
When the MouseLeave event happens(triggering Visible=false), a white box appears in place of the pictureBox or label that was previously there for a split second until the background image fills back in.
I have read up a little bit on using the BackgroundWorker to "pre-load" my pictureBox or labels. I am not sure that i am doing it right. I am very new to programming; i dabble here and there, and do not have any formal training in c#.
I am not looking for anyone to write the code for me, but i also am not objected to that either. A simple example of how to use it should suffice.
I have a background image (1920x1080) on my form. I think this image is actually having a harder time refreshing after the label or pictureBox's visibility is set to false.
private void pictureBox1_MouseEnter(object sender, EventArgs e)
{
this.pictureBox9.Visible = true;
}
private void pictureBox1_MouseLeave(object sender, EventArgs e)
{
this.pictureBox9.Visible = false;
}
I am attempting to use the backgroundWorker DoWork event, but really have no idea what i am doing.
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
this.pictureBox9.Visible = true;
this.pictureBox9.Visible = false;
}
My question is, "How do i use backgroundworker to effectively reduce the lag caused by changing visibilty of my pictureBoxes or lables?
The BackgroundWorker works like this:
BackgroundWorker workerOne = new BackgroundWorker();
BackgroundWorker workerTwo = new BackgroundWorker();
private void MyForm_Load(object sender, EventArgs e)
{
workerOne.DoWork += workerOne_DoWork;
workerTwo.DoWork += workerTwo_DoWork;
}
private void ThingOne_Click(object sender, EventArgs e)
{
workerOne.RunWorkerAsync();
}
private void ThingOne_Click(object sender, EventArgs e)
{
workerTwo.RunWorkerAsync();
}
void workerOne_DoWork(object sender, DoWorkEventArgs e)
{
//This will run as async and not interupt main thread
}
void workerTwo_DoWork(object sender, DoWorkEventArgs e)
{
//This will run as async and not interupt main thread
}
I've included two in the example. Basically the RunWorkerAsync breaks it off in its own thread.
I do not recommend using BackgroundWorker for this because the fact of changing the Visibility of a Visual Element requires the Main Thread and not a Worker Thread. What I recommend in any case is to handle the Opacity so you don't have to load the image again.

C# apply a different file to the same variable

I am trying to create a series of buttons, each play a sound. This sound is retrieved from an OpenFileDialog function. However, I have encountered the issue of one sound being assigned to all of the buttons. I know why this occurring, but I am unsure of how to resolve the issue. Basically, I began by assigning the same algorithms to each button:
openFileDialog = new OpenFileDialog();
if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
fileName = openFileDialog.FileName;
}
And:
soundPlayer = new SoundPlayer(fileName);
soundPlayer.Play();
Unfortunately, this was extremely ugly and so I decided to put each algorithm in to a method and just call the methods to their respective buttons. Like so:
public void openDialog()
{
openFileDialog = new OpenFileDialog();
if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
fileName = openFileDialog.FileName;
}
}
private void button27_Click(object sender, EventArgs e)
{
openDialog();
}
public void playDialog()
{
soundPlayer = new SoundPlayer(fileName);
soundPlayer.Play();
}
private void button1_Click(object sender, EventArgs e)
{
playDialog();
}
However, because openDialog() calls the same variable which receives the file name, each of the buttons calling openDialog() is using the same variable and so playing the same sound.
You have to make the fileName "part" of the Button. You can do it by either:
Using the Tag property of a button and cast to string when retrieving
Create a subclass of a Button called SoundButton and add FileName property of type string
Make a pick.
For example, using a Tag:
public void playDialog(string fileName)
{
soundPlayer = new SoundPlayer(fileName);
soundPlayer.Play();
}
private void button1_Click(object sender, EventArgs e)
{
playDialog((sender as Button).Tag as string);
}
You can make a list of sounds and then play it in a loop one by one:
Creating the list:
List<string> soundsList = new List<string>();
Adding to the list:
sounds.Add(openFileDialog.FileName);
Playing sounds:
foreach(string sound in soundsList)
{
soundPlayer = new SoundPlayer(sound);
soundPlayer.Play();
}
My answer of course is assuming you keep an order of first adding all the sounds you want and then playing them all. You should of course also need to add validation to check that the user has given you a correct sound to add to the list.
EDIT:
After reading your comment, you can also add a sound to Tag property of the button. Then when you want to play a sound of a specific button, you can just play whatever is inside that property of the button.
For example you can override the Click event like this:
private void button_Click(object sender, EventArgs e)
{
string soundFile = (sender as Button).Tag as string;
playDialog(soundFile);
}
This way all sounds are a "part" of the button

Some events dont work in Winform in C#

I am using YoutubeExtractor's dll.. videoDownloader_ProgressChanged and videoDownloader_DownloadFinished events are working in console application but in winform, it doesnt work.. I dont understand why..
private void btnStart_Click(object sender, EventArgs e)
{
string link = textBox1.Text;
start(link);
}
static void start(string link)
{
IEnumerable<VideoInfo> videoInfos = DownloadUrlResolver.GetDownloadUrls(link);
DownloadVideo(videoInfos);
}
private static void DownloadVideo(IEnumerable<VideoInfo> videoInfos)
{
VideoInfo video = videoInfos
.First(info => info.VideoFormat == VideoFormat.Standard360);
var videoDownloader = new VideoDownloader(video, Path.Combine("C:/Downloads", video.Title + video.VideoExtension));
videoDownloader.DownloadFinished += new EventHandler(videoDownloader_DownloadFinished);
videoDownloader.ProgressChanged += new EventHandler<ProgressEventArgs>(videoDownloader_ProgressChanged);
videoDownloader.Execute();
}
static void videoDownloader_ProgressChanged(object sender, ProgressEventArgs e)
{
//some code..
}
static void videoDownloader_DownloadFinished(object sender, EventArgs e)
{
//some code..
}
my second question is, I want to access a form control in a static videoDownloader_ProgressChanged event. e.ProgressPercentage paramter gives me percent of video downloaded. I want to show it in label. But I cant access label because of static event.. I tried to use delegate but nothing changed..
Please modify both Start() and DownloadVideo() routines to instance methods. Remove 'static' keyword from them and event handlers as well.
Thread off 'videoDownloader.Execute()' and BeginInvoke() in the changed/finished handlers.
Don't call methods that take forever, (in computer terms), in GUI event handlers. If it takes more than about 50ms, thread it off. Any net thingy, eg. something with 'YouTube' in it, will take longer than that just to establish a connection!

c# WPF how to repeat MediaElement playback from mediaended event handler without declaring new source?

I'm playing a video in WPF.i want it to loop so what I did is when the mediaended event fires, I play back my video. so this will get me a loop. prob is why do u I have to create new source again? why can't I just call 'play'?
I don't want to do it in XAML as for some reason.
have a look at my code snippet:
string startPath System.IO.Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
public Window1()
{
InitializeComponent();
media.Source = new Uri(startPath + #"playlist.wpl");
media.play();
}
private void Media_Ended(object sender, EventArgs e)
{
media.Source = new Uri(startPath + #"playlist.wpl"); //if i dont put this line, video wont play..seems like it cant get the source
media.Play();
}
or is there a proper way to loop NOT in XAML but in here .cs file?
Instead of resetting the Source at the start of your Media_Ended handler, try setting the Position value back to the start position. The Position property is a TimeSpan so you probably want something like...
private void Media_Ended(object sender, EventArgs e)
{
media.Position = TimeSpan.Zero;
media.Play();
}
You don't even need to set LoadedBehavior as Manual just leave it Play.
And reset your media position on MediaEnded.
The new position of the video should be greater than zero:
private void MediaElement_MediaEnded(object sender, RoutedEventArgs e)
{
media.Position = TimeSpan.FromMilliseconds(1);
}
I make it work setting the UnloadedBehavior="Manual" and the follwing code
private void gifAnimation_MediaEnded(object sender, RoutedEventArgs e)
{
gifAnimation.Position = new TimeSpan(0,0,1);
gifAnimation.Play();
}
Setting the position to Zero didnt work...
I think you should use this code :
private void Media_Ended(object sender, EventArgs e)
{
media.Position = TimeSpan.Zero;
media.LoadedBehavior = MediaState.Play;
}
I hope this will help.
You don't have to set the source again.Just set the position of the mediaelement to the start on the media_ended event
private void MediaElement_MediaEnded(object sender, RoutedEventArgs e)
{
((MediaElement)(sender)).Stop();
((MediaElement)(sender)).Position = new TimeSpan(0, 0, 0);
((MediaElement)(sender)).Play();
}
You may need to set MediaElement.LoadedBehavior to Manual
EDIT
I have tried loading an asf file with the REPEAT tag and its working fine
<ASX version = "3.0">
<TITLE>Simple ASX Demo</TITLE>
<REPEAT>
<ENTRY>
<TITLE>Vista Butterfly Video</TITLE>
<AUTHOR>Microsoft Corporation</AUTHOR>
<COPYRIGHT>(c)2007 Microsoft Corporation</COPYRIGHT>
<REF HREF = "Butterfly.wmv" />
</ENTRY>
</REPEAT>
</ASX>
But i think the inbuilt playlist handling mechanism of mediaelement has some flaws.I recommend following the workaround mentioned in the below link
http://blog.revolunet.com/index.php/general/wpf-mediaelement-asx-workaround
Post comment here if you have any problem

Categories

Resources