SystemSounds only plays one sound - c#

So I am using a win form application using the latest framework for c#.
Here I have a button that plays a sound (asterisk) and then after 5 secs or 20 secs(I let the user pick) I want it to play a different sound (beep in this case) But when it calls the code to play beep the sound I hear is Asterisk.
finally at the end I want another sound to signal that it has finished. I have chosen (Exclamation) but again I hear asterisk.
Does anyone know why I would only hear the one sound?
P.S. I have tried switching the start sound to beep and the "next" sound to asterisk. I clean and rebuild but then the only sound I hear is a beep.
Here is the code behind for the button click
private void btnStart_Click(object sender, EventArgs e)
{
BusinessLayer.ToneApp.PlaySound play = new BusinessLayer.ToneApp.PlaySound();
_countDown = play.IsValid(txtTime.Text);
numreps = play.IsValid(txtReps.Text);
numsets = play.IsValid(txtSets.Text);
lblFinished.Text = "";
play.PlaySoundStart();
_timer = new System.Windows.Forms.Timer();
_timer.Enabled = true;
_timer.Tick += new EventHandler(timer1_Tick);
_timer.Interval = 1000;
_timer.Start();
}
in the timer1_tick event I have
private void timer1_Tick(object sender, EventArgs e)
{
BusinessLayer.ToneApp.PlaySound play = new BusinessLayer.ToneApp.PlaySound();
_countDown--;
if (_countDown < 1)
{
//my code
play.PlaySoundNext();
}
}
and finally here is my playsound
public class PlaySound
{
public void PlaySoundStart()
{
System.Media.SystemSounds.Asterisk.Play();
}
public void PlaySoundNext()
{
System.Media.SystemSounds.Beep.Play();
}
public void PlaySoundStop()
{
System.Media.SystemSounds.Exclamation.Play();
}
public int IsValid(string textToInt)
{
int.TryParse(textToInt, out int timeInSeconds);
return timeInSeconds;
}
}

You should not expect SystemSounds to have any particular sound, because the user can change them. Call Beep or Asterisk to signal something or bring more attention to something. I think Hand is meant to signal an event where something stops unexpectedly or in an unusual way. There is a broader answer regarding this, which also points out the possibility of adding your own system sounds into Windows.
It seems that on latest versions of Windows, the default sounds for Asterisk, Beep and Exclamation are all the same sound. I checked on Windows 10, version 1909. Hand is different and Question has no sound at all. I guess it was made this way, because the first three were used interchangeably due to lack of clear distinction of when it is appropriate to use each of them. And the Question sound probably got removed, because prompts with questions are annoying enough even without the sound.
Custom sounds
You can embed your own sounds into the app. For that you can check out System.Media.SoundPlayer. Embedded resources can be loaded using Assembly.GetManifestResourceStream. Alternatively the sound file can be added to a resources file and accessed though an auto-generated class.

Related

Clicking a button then playing a sound, pauses the UI and if you spam the button continuously plays? [duplicate]

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.

Stop SoundPlayer on mouseUp event

tl;dr version: How can I start playing a sound in the MouseDown event of a WinForms button and stop it from playing in the same button's MouseUp event?
Intermediate C# dev here and I've been trying to write a simple Simon clone.
I'm currently stuck trying to make it play the sound for the colored button only while the user is clicking the button. (I use "button" and "tile" interchangeably. Both refer to the colored button the user will press on the form)
I originally tried this:
public partial class frmMain : Form
{
private SoundPlayer soundPlayer;
private void btnGreenTile_MouseDown(object sender, MouseEventArgs e)
{
soundPlayer = new SoundPlayer(Properties.Resources.greenTileSound)
soundPlayer.Play();
}
private void btnGreenTile_MouseUp(object sender, MouseEventArgs e)
{
soundPlayer.Stop();
}
}
But this didn't stop the sound because the MouseUp event didn't fire due to MouseDown not being finished (still playing the sound which is like 5 seconds long in case someone holds the button for longer than a simple click). As mentioned by Luis Tellez in the comments, SoundPlayer plays the sound on it a new thread...so I have no idea why this code doesn't work now.
So I looked into multithreading and tried this:
public partial class frmMain : Form
{
private Thread soundThread = new Thread(new ParameterizedThreadStart(PlaySound));
// Create stream objects for each sound (needed to allow SoundPlayer to use Resources)
private Stream greenTileSound = Properties.Resources.greenTilePress;
private Stream redTileSound = Properties.Resources.redTilePress;
private Stream yellowTileSound = Properties.Resources.yellowTilePress;
private Stream blueTileSound = Properties.Resources.blueTilePress;
public frmMain()
{
InitializeComponent();
}
private void btnGreenTile_MouseDown(object sender, MouseEventArgs e)
{
soundThread.Start(greenTileSound);
}
private void btnGreenTile_MouseUp(object sender, MouseEventArgs e)
{
soundThread.Abort();
}
// Have to use object as parameter because ParamterizedThreadStart() only takes object arguments
private static void PlaySound(object soundToPlay)
{
SoundPlayer soundPlayer = new SoundPlayer((Stream)soundToPlay);
soundPlayer.Play();
}
}
With the above code, it does not stop playing the sound on MouseUp, and even better it throws a ThreadStateException with the message "Thread is running or terminated; it cannot restart."
As you can probably tell, I only just learned about multithreading while trying to write this code. I have to use ParameterizedThreadStart because the method it calls when the thread starts, PlaySound(), needs to pass a parameter to soundPlayer with the resource corresponding to the colored button that was pressed by the player (a .wav file).
I then thought maybe I should try using soundThread.Suspend() instead of soundThread.Abort() but Suspend is deprecated...
Can anyone point me in the right direction to get the sound to stop on MouseUp? Do I need to work with multithreading? I think my problem just comes down to logic but I am fully stuck. Thank you for any and all help! :)
As a side note, I'm kind of surprised that this question or something similiar has not been asked yet (at least I couldn't find it with google searches or stackExchange searches).
You can see in the documentation that the play() method run in other thread, you can do something else after it and it should run, so your problem with the first approach is something different from what you were thinking.
The Play method plays the sound using a new thread. If you call Play
before the .wav file has been loaded into memory, the .wav file will
be loaded before playback starts. You can use the LoadAsync or Load
method to load the .wav file to memory in advance. After a .wav file
is successfully loaded from a Stream or URL, future calls to playback
methods for the SoundPlayer will not need to reload the .wav file
until the path for the sound changes. If the .wav file has not been
specified or it fails to load, the Play method will play the default
beep sound.
http://msdn.microsoft.com/en-us/library/system.media.soundplayer.play%28v=vs.110%29.aspx

How do I make a "loop" for a game, that runs every (number) of milliseconds?

I've tried to search for this on google and stackoverflow, but I'm not sure what to call it, so I can't find it.
How would I make a "loop" for the C# program, that runs every, say, 100 milliseconds? Similar to what Minecraft calls "ticks", or GameMaker calls "steps".
I can't figure out how to do this. I'm using visual studio, and I have a main window. There are things that I want to execute constantly, so I'm trying to figure out how to make a "step" or "update" function.
If you want it to run for 100 ms you would do this
System.Timers.Timer timer = new System.Timers.Timer(100);
public void Initialize(object sender, EventArgs e)
{
timer.Elapsed+=Elapsed;
}
public void Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
//do stuff
}
Something else you can do, however I don't think this one is as efficient
using System.Threading;
Thread th = new Thread(new ThreadStart(delegate
{
while (true)
{
Thread.Sleep(100);
//do stuff
}
}));
Or, you can download monogame to make more elaborate games in c#
http://www.monogame.net/
It has its own gameTime control.
You could use the Timer control which can be set to tick at a given interval. The interval property is in Milliseconds so you would need Timer1.Interval = 100;
Are you thinking of a Timer?
http://msdn.microsoft.com/en-us/library/system.timers.timer.aspx
Generates recurring events in an application.

How to copy a file as it is being written in C#

I am currently working on Windows Service to copy data from our security cameras as it is being written to the Google Drive directory on the computer for instant upload. The files are accessible immediately after creation by the provided playback software so we would like if possible to immediately copy the data stream, that way we have some video even if the recording is interrupted (the files are 10 minute time blocks).
I currently have a service created which can watch the directory, however I am having some difficulty determining the best way to watch these files. Since they are modified continuously for 10 minutes, I will receive a large number of changed events. I was hoping there might be a way that I can capture the initial creation and start streaming the data to a second file. My concern here is that I need to ensure that I don't overrun the recording stream.
If this isn't possible or relatively simple, then I will just have to detect when the file is no longer being written to by using some logic with the last write time, but I am looking for suggestions on what the best way to do this might be. I am aware of the solutions proposed Here, but I am unsure if they apply to the situation I am dealing with. There are a large number of files within sub-directories so trying to keep track of which files I have are no longer triggering events could get very messy. Does anyone have any suggestions for how to do either of these methods?
Hmmm... You could try using a timer... This way, you can limit when it fires
private Boolean TimeToCheck=false;
public static void Run()
{ Timer timer=new Timer(2000); //2 seconds
FileSystemWatcher fileWatch=new FileSystemWatcher();
fileWatch.Path="DirToWatch";
fileWatch.Filter="fileToWatch";
fileWatch.Changed += new FileSystemEventHandler(OnChanged);
fileWatch.Created += new FileSystemEventHandler(OnChanged);
fileWatch.Deleted += new FileSystemEventHandler(OnChanged);
//If you want rename, you could use the rename event as well fileWatch.Renamed += new RenamedEventHandler(OnRenamed);
timer.Elapsed += new ElapsedEventHandler(timer_done);
watcher.EnableRaisingEvents = true;
timer.Enabled = true; // Enable it
}
private static void OnChanged(object source, FileSystemEventArgs e)
{
if(TimeToCheck)
{
TimeToCheck=false;
timer.Enabled = false; // Enable it
//move the files
timer.Enabled = true; // Enable it
}
}
private static void OnRenamed(object source, RenamedEventArgs e)
{
if(TimeToCheck)
{
TimeToCheck=false;
timer.Enabled = false; // Enable it
//move the files
timer.Enabled = true; // Enable it
}
}
private static void timer_done(object sender, ElapsedEventArgs e)
{
TimeToCheck=true;
}
You could try to do this but to be honest this seems like a hack and I'm skeptical that Windows has any supported method for doing what you're trying to do. Essentially you're trying to listen in on a write stream.
It sounds like whatever solution you're working with right now is a black box so accessing the stream directly probably isn't an option. However, there is another approach. I would look into how you can create a virtual drive with your app in windows. That way you can have the recording application writing to your virtual drive path which will allow you to handle the streams however you like. Which can include writing them to two separate locations at the same time. Both Google drive and some local storage of some kind for example.
Here's a StackOverflow question on how to create virtual drives that should get you started: C#: Create a virtual drive in Computer
Have you looked at the FileSystemWatcher object? If i'm understanding the question correctly, it may be something you may want to use.... If you were to put this security file within a certain directory, you could then use file.copy to move the updated security log into the google drive folder...

VS2010 C# function using a loop

I am currently implementing my final year project as a Music Software Development student.
I am making a software that plays a midi track that is generated earlier in the process.
In my interface, there is a button "play" and a button "stop".
When I click "play", a loop is called that plays this track. In this loop, I call a function from an instance of an other class.
What I would like is that when the user press "pause", the loop is temporary stopped, and when he press "pause" again, it goes back exactly where it was in the loop.
So far, when I press play, the track plays exactly how I want to, but I can't use any other element of my window until the loop is not completly processed.
Here is my code.
private void playStopButton_Click(object sender, RoutedEventArgs e)
{
// Initialising my output midi devices
outDevice.Send(new ChannelMessage(ChannelCommand.ProgramChange, information.bassChannel, information.bassSound));//bass
outDevice.Send(new ChannelMessage(ChannelCommand.ProgramChange, information.guitarChannel, information.guitarSound));//guitar
for (int barNum = 0; barNum < Globals.numberOfBars; barNum++)
{
// playing the first beat
rythmicPattern.play(0, ref outDevice, information, Globals.chordProgression.Bars[barNum].Chord);
//second beat
rythmicPattern.play(1, ref outDevice, information, Globals.chordProgression.Bars[barNum].Chord);
//thrid beat
rythmicPattern.play(2, ref outDevice, information, Globals.chordProgression.Bars[barNum].Chord);
//fourth beat
rythmicPattern.play(3, ref outDevice, information, Globals.chordProgression.Bars[barNum].Chord);
}
}
private void playPauseButton_Click(object sender, RoutedEventArgs e)
{
// test if the track is being played
if (isPlaying)
rythmicPattern.Pause();
else
// if it was already paused, playing back from where I stopped
rythmicPattern.PlayAfterPause(beatNumber);
}
Thank you for your help.
Greg
You must use threading where you can play the sound in another thread, so you can execute pause method
Check this link Multi-threading in .NET: Introduction and suggestions

Categories