Writing XML line every frame in 30FPS - objective-c

Here is my code:
float timeInterval = 1 / [frameRateTextField floatValue];
recordingTimer = [NSTimer scheduledTimerWithTimeInterval:timeInterval
target:self
selector:#selector(recordingTimerSelector:)
userInfo:nil
repeats:YES];
- (void) recordingTimerSelector:(NSTimer*)timer{
NSXMLElement *timecode = [[NSXMLElement alloc] initWithName:#"timecode"];
[timecode setStringValue:[NSString stringWithFormat:#"%#,%#,%#,%#,%#",[DMXChannelArray objectAtIndex:0], [DMXChannelArray objectAtIndex:1], [DMXChannelArray objectAtIndex:2], [DMXChannelArray objectAtIndex:3], [DMXChannelArray objectAtIndex:4]]];
[root addChild:timecode];
time = time + 1;
[theRecordingTime setStringValue:[NSString stringWithFormat:#"%d", time]];
}
Is this the best way to go about doing this? I'm basically making a "recorder" with a resolution of 30FPS. Is there a way to make it go with the actual time, instead of being a separate entity? It might make it more accurate. Like:
10:40:41.0 - record element
10:40:41.3 - record element
10:40:41.6 - record element
Thanks!

You can get the current number of seconds since the reference date by asking NSDate for it.
Get that time interval when you start your timer, and then every time it fires, and subtract the starting time interval from the current one to get the number of seconds since you started.

Related

How to Check Playback Time of Audioplayer increases by 2 seconds

I m trying to write a loop to check that whenever audio player.currenttime increases by 2 seconds then it should execute update view method
- (void)myTimerMethod{
NSLog(#"myTimerMethod is Called");
myTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(checkPlaybackTime:)
userInfo:nil
repeats:YES];
}
- (void)checkPlaybackTime:(NSTimer *)theTimer
{
float seconds = audioplayer.currenttime;
NSLog(#"Cur: %f",audioPlayer.currentTime );
if (seconds = seconds + 2){
[self update view];
}
- (void)UpdateView{
if (index < [textArray count])
{
self.textView.text = [self.textArray objectAtIndex:index];
self.imageView.image = [self.imagesArray objectAtIndex:index];
index++;
}else{
index = 0;
}
}
what is the correct way to write if audio player.currenttimer increases by 2 seconds then do this.
NSLog for current time always shows 0.00. Why is that. It should increase as the audioplayer is playing.
Thanks for help.
What i understood from your given explanation that you want to increment the time-interval something like this
Timer calls after 0.55
Timer calls after 0.60
Timer calls after 0.65
Timer calls after 0.70
& so on.
If that is what you are looking to do. Then i think you can do this way that by changing repeats:YES to repeats:NO so that the timer doesn't repeat, and then in onTimer, just start a new timer with a longer interval.
You need a variable to hold your interval so that you can make it a bit longer each time through onTimer.
Also, you probably don't need to retain the timer anymore, as it will only fire once, and when it does, you'll get a new timer.
float gap = 0.50;
[NSTimer scheduledTimerWithTimeInterval:gap target:self selector:#selector(onTimer) userInfo:nil repeats:NO];
-(void) onTimer {
gap = gap + .05;
[NSTimer scheduledTimerWithTimeInterval:gap target:self selector:#selector(onTimer) userInfo:nil repeats:NO];
}
Hope this helps you
First, try using your float "seconds" in your NSLog rather than the current time.
NSLog(#"Cur: %f", seconds);
current time is not a float, it's an NSTimer object so you would have to use %# in your NSLog text so
NSLog(#"Cur: %#",audioPlayer.currentTime );
Should work as well.
Assuming your audioPlayer is set up correctly, if you're looking for when the timer is at 2 seconds, your if statement will be
if(seconds == 2){
[self update view];
}
if you're looking for each time the timer hits an even number, i.e. 2, 4, 6, etc. your if statement will be
if(seconds % 2 == 0){
[self update view];
}
The % in an if statement is the modulo sign: http://www.cprogramming.com/tutorial/modulus.html
Also, your current if statement is assigning rather than checking the seconds variable. To check it, you need == not =. However, your current if statement will never be true since you're checking a variable by itself + 2. To put this another way, if seconds equals 2, your if statement is asking if 2 == (2+2) or if it it is 4, it's asking if 2 == (4+2). This statement cannot validate as true.
Hope this helps!

NSTimer time increment

I'm a beginner in obj-C for iOS platform and am trying to build a few simple project to build my foundation.
I have a button which increase the NSTimer time for the label, but when I use NSLog to log the time, it uses the value before time increment was implemented. I need to be able to log a updated time (after increment), as I require that value and am implementing more function into the IBAction after I solve this portion.
E.g at 15min I press, the NSLog will read it as "00:15:00.0" rather than "00:35:00.0".
- (IBAction)onSkipPressed:(id)sender {
startDate = [startDate dateByAddingTimeInterval:-1200];
NSLog(#"%#",self.timeLabel.text);
}
Any one know the reason for this issue? And how should I solve it such that NSLog will read it as "00:35:00.0" if I invoke this IBAction at 15min.
EDIT - The start button will start the timer and timeLabel will get the string. Sorry for missing out such a important detail. I don't think there are any other code in the project which is related to this functionality already. Thank you for pointing it out to me.
- (void)updateTimer
{
NSDate *currentDate = [NSDate date];
NSTimeInterval timeInterval = [currentDate timeIntervalSinceDate:startDate];
NSDate *timerDate = [NSDate dateWithTimeIntervalSince1970:timeInterval];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"HH:mm:ss.S"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
NSString *timeString=[dateFormatter stringFromDate:timerDate];
timeLabel.text = timeString;
}
my IBAction to fire the timer
- (IBAction)onStartPressed:(id)sender {
startDate = [NSDate date];
gameTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/10.0
target:self
selector:#selector(updateTimer)
userInfo:nil
repeats:YES];
//hide start button and show timeLabel
startButton.hidden=true;
timeLabel.hidden=false;
}
I went back to do a few revision with tutorials involving NSTimer. And turns out all I was missing was 1 line [self updateTimer]
- (IBAction)onSkipPressed:(id)sender {
startDate = [startDate dateByAddingTimeInterval:-1200];
[self updateTimer];
NSLog(#"%#",self.timeLabel.text);
}
This solve my issue and the timeLabel.text is updated for me to log the information.
Um, why are you passing in negative 1200?
// this subtracts 1200 seconds from your date, no?
startDate = [startDate dateByAddingTimeInterval:-1200];
Shouldn't you do:
// add 30 minutes (60 seconds a minute x 30 minutes) to your time interval
startDate = [startDate dateByAddingTimeInterval:(60 * 30)];
...
NSLog(#"%#",self.timeLabel.text);
Or am I misunderstanding something?

When using a NSTimer in Objective-C, why isn't my code stopping when it gets to 0?

I am using a timer in xcode i have managed to make it count down correctly but when counting down it goes into negatives,
i have tried using an if statement to counter this but it dosnt seem to work here is the code i am using,
IBOutlet UILabel *timelabel;
int MainInt;
NSInteger fred;
NSTimer *timer;
MainInt -= 1;
timelabel.text = [NSString stringWithFormat:#"%i",MainInt ];
MainInt = 20;
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(countdown) userInfo:nil repeats:YES];
if (timelabel.text <= #"0")
{
[timer invalidate];
timelabel.text = #"20";
}
the H is ov my H
Although I believe it would compile
if (timelabel.text <= #"0")
This line doesn't make much sense. It should probably read:
if(MainInt <= 0)
Instead of trying to compare the text value of the label with zero, compare MainInt. Your problem is that you're trying to compare two strings... Technically, you can get the ASCII value of a character and compare it to another, so basically you tried to do something like #"Dog" >= #"Cat" which the runtime will attempt to do but obviously isn't what you want.
There's also a method on NSString called intValue that you could use to pull out an integer representation of the string. You could do
if ([timelabel.text intValue] <= 0)
If you really want to check the timelabel.text use the intValue
if ([timelabel.text intValue] <= 0)
{
timer invalidate];
timelabel.text = #"20";
}
Note: Change to intValue, but take note you should compare it to int also

Frames per second timecode display with NSTimer

I am working on an iPhone/iPad app that needs to display a running timecode clock. I have gotten it to display the correct hours, minutes, and seconds with no problem using this code:
- (void) viewDidLoad {
// Start the Timer method for here to start it when the view loads.
runTimer = [NSTimer scheduledTimerWithTimeInterval: .01 target: self selector: #selector(updateDisplay) userInfo: nil repeats: YES];
}
- (void)updateDisplay {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
NSDate *date = [NSDate date];
// Display each hour, minute, second and frame.
[formatter setDateFormat:#"hh"];
[timecodeHourLabel setText:[formatter stringFromDate:date]];
[formatter setDateFormat:#"mm"];
[timecodeMinuteLabel setText:[formatter stringFromDate:date]];
[formatter setDateFormat:#"ss"];
[timecodeSecondLabel setText:[formatter stringFromDate:date]];
}
The issue is when I need to display frames per second. I know that calculating 1/24 * 1000 gives me how many milliseconds are in one frame. I just don't know how to make the NSDate and NSTimer functions work with this code and allow it to update a UILabel as quickly as needed for running timecode.
Any suggestions?
If your timer is running with the period of 0.01 sec, then it's frequency is 100 frames/sec (well, it's better to say it has 100 function calls per second). But if you need to display the precise time period (cause sometimes the timer may be delayed), then you need to store the previous call date and then use
NSDate* new_date = [NSDate date];
double freq = 1.0 / [new_date timeIntervalSinceDate: old_date];
[old_date release];
old_date = [new_date retain];
Here's a Processing/Java equivalent that's fairly straightforward to repurpose.
String timecodeString(int fps) {
float ms = millis();
return String.format("%02d:%02d:%02d+%02d", floor(ms/1000/60/60), // H
floor((ms/1000/60)%60), // M (edit: added %60)
floor(ms/1000%60), // S
floor(ms/1000*fps%fps)); // F
}

Stop NSTimer when float is 0

I've got a NSTimer and a label which shows the seconds counting down.
-(void)start {
myTimer = [NSTimer scheduledTimerWithTimeInterval:0.01 target:self selector:#selector(showActivity) userInfo:nil repeats:YES];
}
-(IBAction)stop {
[myTimer invalidate];
}
-(void)showActivity {
currentTime = [timeLabel.text floatValue];
currentTime -= 0.01;
timeLabel.text = [NSString stringWithFormat:#"%.2f", currentTime];
if (currentTime == 0) {
[self stop];
ResultViewController *screen = [[ResultViewController alloc] initWithNibName:nil bundle:nil];
screen.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:screen animated:YES];
[screen release];
}
}
- (void)viewDidLoad {
[super viewDidLoad];
timeLabel.text = #"60.0";
[self start];
}
So when the time is 0, the timer should stop and the ResultViewController should load, but when I do it the timer still counts down into negative numbers and nothing happens.
Is there anybody who can help me?
Thank you :)
0.01 doesn't have an exact floating point binary representation, so your float will never get to exactly zero. Use <= instead of == in your comparison.
Try something like this:
if(currentTime <= 0.0)
...
What you're suffering from is floating point drift. It's a well known phenomenon.
Floating point arithmetic isn't "precise" oftentimes (see http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems ) . Change the check to if (currentTime <= 0.0) and you'll be fine.
Not all numbers can be stored accurately with floating point variables. Just as 1/3 can't be represented with finite digits in base 10, 1/10 can't be represented with finite digits in base 2. What you end up with is rounded to 0.10000000000000001 or close. So when you subtract 0.1 from that, you don't quite get 0.
The most robust solution to this is to store your time as milliseconds in an integer and divide it when you want to update the label. Don't bother going back and forth from the label to the number either. The canonical storage of the number should be as a number. The label is just to display it.
Edit:
For everybody recommending that he just change to <= instead - this is just a hack that barely scrapes by. Floating point representation of 0.1 is often 0.10000000000000001. What happens when you subtract 0.1 from that? It's still above 0. The conditional only triggers when it reaches almost -0.1, which isn't expected behaviour from the app. This is a bad solution.
ResultViewController should just alloc init instead of the alloc initWithNibName set to nil.
current time comparison should be put as if (currentTime <= (float)0.0) or similar (Reason for it refer to:this thread)
Better not compare against an int. Try to do this:
if (currentTime == 0.0) {