Advertise Mobile SDKs Books Events Forum News Social Networking Support Us
Follow @iphonedevsdk on Twitter

Interface 2, Advanced iOS
Mockup & Code Gen
($9.99)

Make your own iPhone apps
and run them live!
(free)

Pic Frame Dynamo: Photo Editing
($0.99)

Abiliator
($1.99)

Want your application or service advertised on iPhone Dev SDK?

Go Back   iPhone Dev SDK Forum > iPhone SDK Development Forums > iPhone SDK Development

Reply
 
LinkBack Thread Tools Display Modes
Old 05-10-2009, 11:54 PM   #1 (permalink)
syd
New Member
 
Join Date: Feb 2009
Posts: 17
syd is on a distinguished road
Default Please help with metronome sample code analysis!

So I have been trying to figure out the metronome sample code from apple.
I am not interested in the animation, i get that, at least most of it. What i would want to understand is how to get the timer working, just the metronome itself. Usually if i want to separate two events like the tick and tock sound in the program with a specified time interval, i would just put a delay for the required number of seconds. I don't get where the delay is coming between the tick and tock sounds. How is the program waiting lets say at 60bpm for 1 sec in their code? I can't seem to figure out.
I just want to be able to setup the timer and figure out the delays required to set the intervals between two events.

I am pasting the sample code from apple which i think would be relative to the time calculations:

- (void)startDriverTimerid)info {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

// Give sound thread high priority to keep the timing steady
[NSThread setThreadPriority:1.0];
BOOL continuePlaying = YES;

while (continuePlaying) { // loop until cancelled
// Use an autorelease pool to prevent the build-up of temporary date objects
NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];

[self playSound];
[self performSelectorOnMainThread:@selector(animateArmTo OppositeExtreme) withObject:nil waitUntilDone:NO];
NSDate *curtainTime = [NSDate dateWithTimeIntervalSinceNow:self.duration];
NSDate *currentTime = [NSDate date];

// wake up periodically to see if we've been cancelled
while (continuePlaying && ([currentTime compare:curtainTime] != NSOrderedDescending)) {
if ([soundPlayerThread isCancelled] == YES) {
continuePlaying = NO;
}
[NSThread sleepForTimeInterval:0.001];
currentTime = [NSDate date];
}
[loopPool release];
}
[pool release];
}


PLEASE, PLEASE HELP ME UNDERSTAND THIS!
syd is offline   Reply With Quote
Old 05-11-2009, 03:29 AM   #2 (permalink)
Registered Member
iPhone Dev SDK Supporter
 
smasher's Avatar
 
Join Date: Jul 2008
Location: San Mateo, CA (San Fran)
Posts: 3,858
smasher will become famous soon enough
Default

The Metronome example uses threading; if you're not familiar with threading, then I would look up NSTimer instead. It will be easier to get your timer working.
__________________

Free Games!
smasher is offline   Reply With Quote
Old 05-11-2009, 10:14 PM   #3 (permalink)
syd
New Member
 
Join Date: Feb 2009
Posts: 17
syd is on a distinguished road
Default

Quote:
Originally Posted by smasher View Post
The Metronome example uses threading; if you're not familiar with threading, then I would look up NSTimer instead. It will be easier to get your timer working.
Is there any reference that I can get for understanding threading? I know the concept in a generic sense but i just don't understand the implementation of it in this context? How am i making delays between one action and the other?

Appreciate your response, please help if you can.
syd is offline   Reply With Quote
Old 05-12-2009, 02:14 AM   #4 (permalink)
Registered Member
iPhone Dev SDK Supporter
 
smasher's Avatar
 
Join Date: Jul 2008
Location: San Mateo, CA (San Fran)
Posts: 3,858
smasher will become famous soon enough
Default

Code:
- (void)startDriverTimer(id)info {
     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
     
     // Give sound thread high priority to keep the timing steady
     [NSThread setThreadPriority:1.0];
     BOOL continuePlaying = YES;

     while (continuePlaying) { // loop until cancelled
          // Use an autorelease pool to prevent the build-up of temporary date objects
          NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];

          [self playSound];
          [self performSelectorOnMainThread:@selector(animateArmTo OppositeExtreme) withObject:nil waitUntilDone:NO];
          NSDate *curtainTime = [NSDate dateWithTimeIntervalSinceNow:self.duration];
          NSDate *currentTime = [NSDate date];

          // wake up periodically to see if we've been cancelled
          while (continuePlaying && ([currentTime compare:curtainTime] != NSOrderedDescending)) {
               if ([soundPlayerThread isCancelled] == YES) {
               continuePlaying = NO;
               }
               [NSThread sleepForTimeInterval:0.001];
               currentTime = [NSDate date];
          }
     [loopPool release];
     }
[pool release];
}
Okay - this method has two while loops - the big while loop around everything, and the little while loop around the sleep command.

The big while loop plays the sound, calls the animation, and creates a date called "curtainTime" that contains the (current date + self.duration). Then control passes into the little while loop, which loops until either we reach curtainTime, or the thread gets canceled. Once curtainTime is reached, we iterate the big loop again (play sound, call animation.)

As far as I can tell, the timing must be coming from thet self.duration. What is duration being set to? One second?
__________________

Free Games!
smasher is offline   Reply With Quote
Old 05-12-2009, 10:27 PM   #5 (permalink)
syd
New Member
 
Join Date: Feb 2009
Posts: 17
syd is on a distinguished road
Default

Thanks for your help, I appreciate it indeed, in fact i will buy your app as a token of my appreciation

while (continuePlaying && ([currentTime compare:curtainTime] != NSOrderedDescending)) {
if ([soundPlayerThread isCancelled] == YES) {
continuePlaying = NO;
}

I knew this is the line of code that was implementing the timing, but could not figure out that it was waiting for current time to be same as curtain time. Duration is indeed 60/bpm which is what the metronome uses to calculate the delay.

Also do you understand why, after we get out of the small loop, they have
[NSThread sleepForTimeInterval:0.001];
currentTime = [NSDate date];

why does the thread need to sleep? would this not mess up the timing? Is .001s a standard sleep duration? Also I could not figure out why they have the current time calculated here again, cos the next time we get back in the big loop, we have
NSDate *currentTime = [NSDate date];


In my app , i want this metronome running, and give me interrupts at specific time intervals. I would like to play a short sound as they do but i also need to insert 2 images at the same click, small images maybe 20x 20. Do you think i will have to do threading for this? Also why do you think this example has used threads, instead of using a timer/NSTimer?

Thanks a bunch! Really appreciate it!
syd is offline   Reply With Quote
Old 05-13-2009, 02:22 AM   #6 (permalink)
Registered Member
iPhone Dev SDK Supporter
 
smasher's Avatar
 
Join Date: Jul 2008
Location: San Mateo, CA (San Fran)
Posts: 3,858
smasher will become famous soon enough
Default

Thanks, I can always use more sales.

Quote:
Originally Posted by syd View Post
Also do you understand why, after we get out of the small loop, they have
[NSThread sleepForTimeInterval:0.001];
currentTime = [NSDate date];

why does the thread need to sleep? would this not mess up the timing? Is .001s a standard sleep duration?
The small loop checks the time, sleeps a bit, then repeats. There's no need to check the time a million times a second - so the thread sleeps for a bit. I wouldn't say its a standard sleep duration - if it were shorter you'd waste more CPU/battery, if it were longer then the timing might be off (it would take longer to notice that you've reached the curtain time.)

Quote:
Also I could not figure out why they have the current time calculated here again, cos the next time we get back in the big loop, we have
NSDate *currentTime = [NSDate date];
The small loop repeatedly checks currentTime against curtainTime (waiting for currentTime to reach curtainTime). So we need to update currentTime after every sleep, to find out what time it is now.

NSDate is not a counter that keeps track of current time - it just stores the time that [NSDate date] was called. So if you didn't update currentTime after sleeping, then the loop would never exit (currentTime would never increase).

Quote:
In my app , i want this metronome running, and give me interrupts at specific time intervals. I would like to play a short sound as they do but i also need to insert 2 images at the same click, small images maybe 20x 20. Do you think i will have to do threading for this? Also why do you think this example has used threads, instead of using a timer/NSTimer?
Some people have complained that timers are not accurate enough - that you can't get more accurate than 50-100 ms. That's probably why this example uses threads. I haven't noticed this in my app, but I'm only running at 30 frames per second. If you don't need super tight timing, it's certainly easier to use NSTimer.
__________________

Free Games!
smasher is offline   Reply With Quote
Old 05-13-2009, 11:20 PM   #7 (permalink)
syd
New Member
 
Join Date: Feb 2009
Posts: 17
syd is on a distinguished road
Default

Thanks a bunch this has been very helpful..
I am going to check out your workout app, I hope it helps me keep up with my gym
syd is offline   Reply With Quote
Old 08-13-2010, 12:47 PM   #8 (permalink)
Registered Member
 
Join Date: Sep 2009
Posts: 7
Trotelj is on a distinguished road
Default

Hi!
In this particular code, there is a delay in tempo.
The Metronomes 210 is actually 180 in reality.
I have managed to get it to 210 -> 200, but it is still not right.

Can someone tell me why the delay (we are working with NSDate, I do not see why such a delay) and is there a way to get rid of it.

I figured I could find a formula and alter the tempo, but is there another way?

Meny thanks for your replies,
Trotelj
Trotelj is offline   Reply With Quote
Old 08-13-2010, 01:54 PM   #9 (permalink)
Cocoa Junkie
 
Duncan C's Avatar
 
Join Date: Dec 2008
Location: Northern Virginia
Posts: 6,003
Duncan C has a spectacular aura about
Default

Quote:
Originally Posted by Trotelj View Post
Hi!
In this particular code, there is a delay in tempo.
The Metronomes 210 is actually 180 in reality.
I have managed to get it to 210 -> 200, but it is still not right.

Can someone tell me why the delay (we are working with NSDate, I do not see why such a delay) and is there a way to get rid of it.

I figured I could find a formula and alter the tempo, but is there another way?

Meny thanks for your replies,
Trotelj
This is a pretty awful way to do timing, truth be told.

The code in the thread is creating a pile of NSDate objects, and then draining it's auto-release pool to get rid of them. That's memory wasteful.

There is a much simpler, cleaner way to check times. NSDate has a class method +timeIntervalSinceReferenceDate that gives you a double precision value of the number of seconds since some arbitrary date (1 January 1970?) with very high accuracy.

You can use timeIntervalSinceReferenceDate to check the amount of elapsed time without creating a bunch of NSDate objects.

The app is also written using NSThreads, which are about 2 generations out of date. With Mac OS 10.5 and iOS 3, we were told to use NSOperations and NSOperationQueues instead. Much simpler and cleaner. Having written a BUNCH of code using NSThreads, I would have to agree that NSOperationQueues are much, much cleaner and easier to use.

With Mac OS 10.6 and iOS4.0, we have an even better way to do async processing: blocks and Grand Central Dispatch. I haven't had occasion to use GCD yet, but it looks cleaner and easier still then NSOperationQueues.

In short, don't look at the timing code in Metronome too closely. It isn't a sterling example of the right way to do things.
__________________
Regards,

Duncan C
WareTo

Check out our apps in the Apple App store


Check out this password generator app that shows various techniques including using a data container singleton object to share data between objects in your project.

See this tutorial on using UIView animations and layer animations:

See this thread on generating random, non-repeating text

Check out a very cool Macintosh Kaleidoscopes app called ScopeWorks that we released to the Mac App store.
Duncan C is offline   Reply With Quote
Reply

Bookmarks

Tags
metronome, nsdate, sounds, timer

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On



» Advertisements
» Online Users: 314
6 members and 308 guests
givensur, guusleijsten, jbro, mer10, n00b, yomo710
Most users ever online was 1,387, 04-10-2012 at 04:21 AM.
» Stats
Members: 175,649
Threads: 94,113
Posts: 402,880
Top Poster: BrianSlick (7,990)
Welcome to our newest member, Anwerbl
Powered by vBadvanced CMPS v3.1.0

All times are GMT -5. The time now is 09:05 PM.
Powered by vBulletin® Version 3.8.0
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.3.0