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
Related
I am working in Visual Studio 2017 in C# WinForms- The project is based on a conversion from VB6 to C#. What it does right now is that I press a GetQue-button which gather a key that resembles a document, thereafter that document is exported through mail to another mail.
Now for the last point I need to create a Timer where it executes all of this code every 60sec.
I really appreciate all types solutions and I really do not know a lot about timers, but I would really like some simple explanation as well.
Note that I have only used a timer in an simple console app once.
As this code below, the timer will execute the button click which starts the process and it is done within a 60sec interval.
private void StartTimer_Tick(object sender, EventArgs e)
{
if (bRunning == false)
{
bRunning = true;
BtnGetQue_Click(sender, e);
bRunning = false;
}
}
I'm making a quiz game and want to make sure that the user does not get additional answering time by exiting the app (without shutting it down).
My current timer uses Time.deltaTime. I'm thinking of replacing this with something like DateTimeOffset.Now.ToUnixTimeMilliseconds() (epoch time) or Time.realtimeSinceStartup (not sure if this one works). A solution to detect when the user closes the app would also work.
There are three built-in functions that might do what you want. There is OnApplication.Quit (does not work on mobile), OnApplication.Pause, and OnApplicationFocus.
I personally like using OnApplicationPause instead of OnApplicationFocus as focus is called on some phones when the keyboard is brought up. I have found that pause is called whenever a user hits the home button, closes the app, their phone dies, turns off their phone, etc.
The great part about the OnApplicationFocus and OnApplicationPause is that there is a bool parameter passed in to let you know whether you are unfocused or focused / unpaused or paused.
If you just want to know how long it has been since the last time the app is opened, you can easily stored a variable locally after an OnApplicationPause is called when the bool is true, then when it is false, you can detect how much time has elapsed. As the local variable will not persist if the user quits the game, you will need to also look into some sort of save/load implementation. There are already many good answers on StackOverflow for how to save data in Unity, so if you need help with that I can add a link.
As for the OnPause example here is how I would use it.
private long lastTimePaused = 0;
private void Awake
{
// setting our paused time to the start time
lastTimePaused = DateTimeOffset.Now.ToUnixTimeMilliseconds();
}
void OnApplicationPause(bool pauseStatus)
{
if(pauseStatus)
{
lastTimePaused = DateTimeOffset.Now.ToUnixTimeMilliseconds();
// save this lastTimePaused if you want the data to persist between a user quitting the app
// and coming back
}
else
{
Debug.Log("Our elapsed miliseconds is: " + (DateTimeOffset.Now.ToUnixTimeMilliseconds() - lastTimePaused));
}
}
If you like, you can also use OnApplicationFocus together with OnApplicationPause. Something like:
private long lastTimePaused = 0;
private void Awake
{
// setting our paused time to the start time
lastTimePaused = DateTimeOffset.Now.ToUnixTimeMilliseconds();
}
void OnApplicationPause(bool pauseStatus)
{
HandlePause(pauseStatus);
}
void OnApplicationFocus(bool hasFocus)
{
HandlePause(!hasFocus);
}
private void HandlePause(bool isPaused)
{
if(isPaused)
{
lastTimePaused = DateTimeOffset.Now.ToUnixTimeMilliseconds();
// save this lastTimePaused if you want the data to persist between a user quitting the app
// and coming back
}
else
{
Debug.Log("Our elapsed miliseconds is: " + (DateTimeOffset.Now.ToUnixTimeMilliseconds() - lastTimePaused));
}
}
I am not sure what cases you would like to detect when a user is suspended, but first, try OnApplicationPause to see if it handles everything you need. If it does not, you can also combine it with OnApplicationFocus.
Im new to C#!
So my Problem: I got a C# Demo Program from an extern company, the program sets the settings of an extern device, than initialize it and starts recording the Data. The Data is written into the Console and streamed into a CSV at a Location i can choose. After pressing a Key in the Console the Recording stops. I am trying now to write a short GUI that starts and stops this Recording.
What I did:
I converted the main-method, which started the recoding, into a normal static method and deleted all writelines so the console doesnt start, than I created a Windows Form with 2 Buttons, one Start and One Stop. If I press Start, the Recording starts, but I cant do anything with the Gui it is like freeezed, a Console still appeares and i can only stop the process by pressing a key in the console.
Here is a snippit of the Console Code:
class BHJKL
{
system
private static A;
private static B;
// This method will be executed every time new data is received
static void OnNewDataReceived(object sender, NewDataEventArgs eventArgs)
{
//some code in here
using (StreamWriter file = new StreamWriter(#"C:\Users\XYZ\File_Trial" + DateTime.Now.DayOfYear + ".csv", true))
{
//Writeline data..
}
}
}
// This was the Main Method before i changed it
public static void Record()
{
// Here is some Code that configure the Settings of the device
// initialize device
// MORE CODE USING THE COMPANYS EXTERN LIBRARYS TO START THE DEVICE
//start device
deviceManager.DeviceStart();
while (!Console.KeyAvailable) // as long as no key is pressed do...
{
Thread.Sleep(100); // do nothing, let the event processing thread that is managed by the library handle incomming data
}
//stop device
deviceManager.DeviceStop();
//unsubscribe event
deviceManager.NewDataReceived -= OnNewDataReceived;
//deinitialize device
deviceManager.DeinitializeDevice();
//dispose device
deviceManager.Dispose();
}
}
My Attempt:
Changing the main method into static Recording.
Than by Pressing the Start Button, call the method.
Write this at the end of the method:
while (Rec==true)
{
Thread.Sleep(100);
}
By Pressing the Stop Button: set.Rec(false)
But after Pressing the start Button, i cant press the stop button anyome.
I hope someone can understand my Problem and can give me some advices.
Thread.Sleep blocks your UI from doing anything. Consider using a System.Windows.Forms.Timer
Rather than sleeping in a loop, you should just let your Start method return. Move all of the code that comes after the sleep loop into your Stop button's click event handler.
(Depending on how the code is structured, you may also have to switch deviceManager from being a local variable to being a field in the class)
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.
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