I'm trying to make a "notification sound" that plays at certain time specified in the app, but for some reason it won't work. If I compare against a time interval it keeps playing the sound in a loop, but I cannot get it to play the sound once at the very moment the time matches.
System.Media.SoundPlayer player = new System.Media.SoundPlayer(#"c:\Windows\Media\ding.wav");
private void timer1_Tick(object sender, EventArgs e)
{
TimeSpan currentTime = DateTime.Now.TimeOfDay;
if (currentTime == TimeSpan.Parse("15:00"))
{
player.Play();
}
}
The timer compares current time every 100ms so I don't think it's down to timing but maybe I'm just missing something. Any ideas what's wrong or if I should use a different approach?
Related
is there a way to change the update speed of the LibVLCSharp MediaPlayer TimeChanged-Event?
I use this event to update the remaining playtime of my video. But this is too slow for my purpose. I would like to update the remaining time every 10ms. Is that possible?
My Code:
private void InitMediaPlayer()
{
vlc = new LibVLC(true, "");
videoClipMediaPlayer = new MediaPlayer(vlc);
videoClipMediaPlayer.TimeChanged += MediaPlayerTimeChanged;
}
private void MediaPlayerTimeChanged(object sender, MediaPlayerTimeChangedEventArgs e)
{
long RemainingTimeMS = videoClipMediaPlayer.Media.Duration - e.Time;
RemainingPlayTime = new TimeSpan(0, 0, 0, 0, Convert.ToInt32(RemainingTimeMS));
// this is only called every 250 milliseconds
}
That's not possible to increase the rate of callbacks, because libvlc doesn't let you do that. The events are triggered synchronously on the playback thread, and having callbacks that takes too long would stutter the video.
Instead, you could have your own timer and interpolate the video's time, and resync the counter at each TimeChanged. You would need to save the vodeo's time along with the current computer time, and in each of your timer's callback, newVideoTime = lastVideoSyncTime + (now - lastSyncTime)
I'm going to make a rhythm game.
music playing time is variable which change by music playing in millisecond
List is a float list which have the time(float second) I filled , let me to access it and use for compare with music playing time to instance object .
when list time = music time then instant object.
but sometimes will missing(not found value in list but value is really exist in list).
Here is my assumption.
I think List.indexOf performance are not good and thread have some delay.
Music playing time change every millisecond , a little delay from unity or others will cause missing(doesn't entering if statement)
I don't know if it's correct.
Could any one help me.
Here is my code.
IEnumerator Execute(MethodDelegate Start,MethodDelegate Stop)
{
while (true) {
int res = result.IndexOf ((float)System.Math.Round (GameObject.Find ("Music").GetComponent<AudioSource> ().time, DigitalAdjust)-TimeAdjust);
if (res!=-1) {
if (res == result.Count-2) {
Stop.Invoke ();
print ("CoroutineStop");
StopCoroutine (_Execute);
}
//execute
num=Positoin[res];
print (res);
Start.Invoke();
}
yield return null;
}
}
Thanks.
Chances are that you are correct. You might miss some if statement because you don't match the millisecond exactly. Here are some things that could help:
It you game reaches 60 FPS (the usual rate for a smooth rendering), each frame will take around 16 milliseconds. If you have events that must trigger at exact milliseconds you will miss some because your Execute function calls are separated by around 16ms (a coroutine is called once per frame).
A solution to this is remember the last time the Execute function was called and check everything in between:
private float _lastTime;
IEnumerator Execute(MethodDelegate Start,MethodDelegate Stop)
{
while (true) {
// here your code must check all the event between _lastTime and Time.time
var lastTimeMilliseconds = (int)(_lastTime*1000);
var currentTimeMilliseconds = (int)(Time.time*1000);
for(int time = lastTimeMilliseconds+1; time <= currentTimeMillisedons; time++)
{
// let's say last frame was at time 1000ms
// This frame occurs at time 1016ms
// we have to check your list for events that have occured since last frame (at time 1001, 1002, 1003, ...)
// so we have a for loop starting at 1001 until 1016 and check the list
int res = result.IndexOf ((float)System.Math.Round (time, DigitalAdjust)-TimeAdjust);
if (res!=-1)
{
if (res == result.Count-2)
{
Stop.Invoke ();
print ("CoroutineStop");
StopCoroutine (_Execute);
}
//execute
num=Positoin[res];
print (res);
Start.Invoke();
}
}
// At the end, remember the time:
_lastTime = Time.time;
yield return null;
}
}
Check the Time class, you also have access to Time.deltaTime to know the time elapsed between two frames, if that helps.
EDIT:
As you requested in comment, I added some bit of code from your example to explain better this idea. Note that I don't know what your variables do so you will have to adapt. For instance, Time.time gives that time since app start. You will likely need to adapt this use the time since you started the audio
Another important thing:
GameObject.Find must look in all the objects. It is really slow and shouldn't be used every frame
GetComponent looks for all your scripts and is slow as well. It shouldn't be used every frame.
Instead, do this:
private AudioSource _audioSource;
private void Start()
{
_audioSource = GameObject.Find ("Music").GetComponent<AudioSource> ();
}
This will retrieve the source only once. Then in your code you simply call
_audioSource.time;
I am using timer to connect several audio files together. There are a list of audio files and the timer will read files one by one. Once there is an audio read, it will be played. The goal is to play the audio file right after the previous one when it is finished(without any break).
(I am using Naudio)
Here is the code:
private void timer_key_Tick(object sender, EventArgs e)
{
if(!isPlaying)
{
//play the current audio
DirectSoundOut dso = sounds2[key_indexer];
dso.Play();
targetMusics.Add(dso);
}
else
{
foreach (DirectSoundOut dso in targetMusics)
{//stop the current audio
dso.Stop();
}
targetMusics.Clear();
key_indexer++; //switch to the next audio
if (key_indexer >= myMT.Keys.Count)
{
key_indexer = 0;
timer_key.Stop();
}
}
isPlaying = !isPlaying;
}
However, the fact is, when the first music finished, the second one didn't play at once. It comes after one second break. Is this the problem about timer itself? How should I change it?
Thanks for the help from #HansPassant. I made a mistake about logic in this timer. Here is the correct code after I applied his suggestion:
//stop the current playing
foreach(DirectSoundOut d in targetMusics)
{
d.Stop();
}
targetMusics.Clear();
//stop the entire process
if (key_indexer >= myMT.Keys.Count)
{
key_indexer = 0;
timer_key.Stop();
}
else
{ //play the current audio
DirectSoundOut dso = sounds2[key_indexer];
targetMusics.Add(dso);
dso.Play();
key_indexer++;
}
basically I have a countdown timer with in my game. What I basically want to do is continue my timer playing even if I close out of my application and play it again, I want the timer to continue counting down. Kind of like clash of clan when the counter is still work when the app is closed. For example: if I exit the game and the timer is on 1:30 (1 minute, 30 seconds). Then if I restart the game 30 seconds later, the timer should show 1:00 (1 minute, 0 seconds) Or if I close the game 30 seconds later, the timer should show 1:00 (1 minute, 0 seconds)
So far this is as far as I've got:
public class TimeManager: MonoBehaviour {
public Text timer;
float minutes = 5;
float seconds = 0;
float miliseconds = 0;
public int curHealth;
public int maxHealth = 3;
void Start ()
{
curHealth = maxHealth;
}
void Awake ()
{
if (PlayerPrefs.HasKey("TimeOnExit"))
{
var x = DateTime.Now - DateTime.Parse(PlayerPrefs.GetString("TimeOnExit"));
PlayerPrefs.DeleteKey("TimeOnExit");
}
}
void Update(){
if(miliseconds <= 0){
if(seconds <= 0){
minutes--;
seconds = 59;
}
else if(seconds >= 0){
seconds--;
}
miliseconds = 100;
}
miliseconds -= Time.deltaTime * 100;
//Debug.Log(string.Format("{0}:{1}:{2}", minutes, seconds, (int)miliseconds));
timer.text = string.Format("{0}:{1}", minutes, seconds, (int)miliseconds);
}
private void OnApplicationQuit()
{
PlayerPrefs.SetString("TimeOnExit", DateTime.Now.ToShortTimeString());
}
}
TimeOnExit is good but you also need to store either the target time or remaining time of each countdown timer (in case you have more than one - e.g., multiple Woodcutters producing Wood).
Then, in the startup code for the game, you need to run through your game loop once per second that the user was absent. If a timer would have triggered an event, you trigger that event in this loop (Woodcutter adds 1 Wood to Barn).
If you've ever seen a game with a progress bar at startup, there's a good chance that's part of what's going on.
Depending on your game and how long the user was gone, you might need to simulate multiple iterations of the same timer (Woodcutter adds 1 Wood to Barn and then starts working on the next Wood - over and over until the time is caught up).
Finally, you would need to re-instantiate the actual timers that existed and need to continue during live play. Be sure to figure out where they are within the 5-minute loop. If all of the timers are off by a few seconds, nobody will notice but if a restart means they all line up, that will seem strange.
Once you get sophisticated, there are techniques that are faster than a second-by-second (or whatever time period makes sense for your game) simulation of the time that went by but that's a good place to start.
Here's a hint: If you store an array of the target times and what event should trigger, it could be easy enough to cycle through the ones that are in the past and trigger them in order. Be sure to insert new target times into the array for repeating events.
Good Luck!
I am trying to implement a simple counter in my XNA game. Thought this would be simple enough. I have the following code:
elapsed = gameTime.ElapsedGameTime.TotalMilliseconds;
timer -= (int)elapsed;
if (timer <= 0)
{
timer = 10; //Reset Timer
}
But elapsed never changes from 0.0. Am I missing something obvious here? I suspect I am. I have gameTime declared at the top and initialised as usual.
As asked, here is a bit more code:
public class Game1 : Microsoft.Xna.Framework.Game
{
private GameTime zombieTime;
public Game1()
{
zombieTime = new GameTime();
// Other (unrelated) stuff here
}
protected void AddZombie()
{
elapsed = zombieTime.ElapsedGameTime.TotalMilliseconds;
timer -= (int)elapsed;
if (timer <= 0)
{
timer = 10; //Reset Timer
Zombie zombie = new Zombie(ScreenWidth, ScreenHeight, random);
zombie.LoadContent(this.Content, "ZombieSprites/ZombieLeft1");
zombies.Insert(0, zombie);
}
}
protected void Update()
{
AddZombie();
// Other game update stuff here
}
}
I am sorry, I believed the original code snippet would have been enough. I read some pages online where people posted examples of a timer and used the method I have used above. I understand some of the comments made here about the update going fast enough so that elapsed time will always be 0.
You're not using the correct GameTime. zombieTime is never updated by anything so it will always be zero'd out. The GameTime you want to use is passed into the Update() function already for you.
The correct way to do it would be like this:
protected void AddZombie(GameTime gameTime)
{
float elapsed = gameTime.ElapsedGameTime.TotalMilliseconds;
timer -= (int)elapsed;
if (timer <= 0)
{
timer = 10; //Reset Timer
// Rest of stuff goes here
}
}
protected void Update(GameTime gameTime)
{
AddZombie(gameTime);
}
http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.gametime_members.aspx
Elapsed game time is the time since the LAST update. TOTAL game time in the cumulative game time...
So, unless you're doing a lot of work you're not showing, you're gonna be taking no time at all to update, so a value of 0 is quite sensible
try shoving a sleep statement in there and see if elapsed time goes up.