Using NSProgessIndicator as playback bar - objective-c

I am currently writing a music playing program for OS X. I am implementing an NSProgessIndicator to show the current playback progress of a song as it plays. How can I efficiently update the progress once per second without getting off-sync with the music?
Ideally I want something like iTunes has where it also has numbers to show the exact playback time and time remaining:
Currently the only thing I can think of is to use an NSTimer with the interval set 1 second and force it run on the main thread through that. However, this seems very inefficient and also like it might not keep perfect sync. Is there a better way to go about this?

You can use the timer just to update the info, in this case the audio current time. AVAudioPlayer has a property with the same name currentTime which will return the time for you as NSTimeInterval(seconds).

Related

gsap, revert animation after play

I'd like to play an animation with gsap, but after it has finished playing, I want to reset it. Like after playing that animation, reset, after it is finished. Without clicking anywhere or calculating the play time, sleeping or waiting the process. Just simply something like:
TweenLite.to(thing, 1, {x:'-20px'}).reset();
(ideally, there is no reset call in gsap.. how to acieve this?)
I can't get it to work with .seek(), .time(), .pause().
Those always interrupt the animation.
Preferable I want to use a simple TweenLite, or if it has to, a TimelineLite.
Im searching / looking for it since hours..
There are many ways to do it, but here's a simple one:
TweenLite.to(thing, 1, {x:-20, onComplete:function() {
this.pause(0); //seeks the tween (this) to 0 (playhead's starting position) and pauses immediately.
}});
Does that help?

How to hear sound from mpmovieplayer at a specific time using UISlider?

I'm working on an iOS movie editor project. For this editor, i use MPMoviePlayer to show the video file selected by the user.
I use custom controls, and I have a UISlider that enables the user to move the player's currentTime position. When the user touches the slider, movie is paused and its currentTime changes along with the UISlider's value.
Everything works perfectly, but now i need to let the user hear the sound at this currentTime position.
For those who know iMovie, when you move your mouse over a movie event, you see the image and hear the sound at this position, and that's what i'd like in my editor.
I've tried to call player's play method with à NSTimer to stop after 0.2 seconds, but the result is kind of messy.
Has anyone already achieved to do something like this ?
Thanks !
Best regards.
Seeking takes time; that's why you've ended up using a timer. The real problem here is that MPMoviePlayerController, while convenient because it gives you controls, is a blunt instrument; it's just a massive simplified convenience built on top of AVFoundation. But you don't need the built-in controls, so I would suggest throwing away your entire implementation and getting down to the real stuff, using AVFoundation instead (AVPlayer etc). Now you have a coherent way to seek and get a notification when the seek has completed (seekToTime:completionHandler:), so you'll be able to start playing as soon as possible. Plus, AVFoundation is the level where you'll be doing all your "editing" anyway.

MonoTouch - Location services in background

I have an app using MonoTouch which requires to capture GPS data every 2 mins in background. I found two ways to do it
using startMonitoringSignificantLocationChanges- works in background but not every 2 mins.
Using Timer and StartUpdatingLocation - Timer will be called every 2 mins and then update location.
The problem with startMonitoringSignificantLocationChanges is it doesn't get fired every 2 mins. So i cant use it. The other option of using Timer is better since it gives me a handle over time. But, will it run till my app is in the background for example one hour? Usually, ios apps gets 10 mins in background.
Thanks
You could set app's UIBackgroundModes to location and gets current location changes in background. Battery killer yet works.
Other way is interpolate data from Significant Location Changes between UIApplicationLaunchOptionsLocationKey events.

How to improve (time) resolution of touches locationInView

I am trying to program an iPhone app where the user can handwrite. I am using touchesmoved to track the user's finger, but I get between 30 and 50 updates a second. For quick finger movements, this is often no enough to get smooth letters: small letters like i often just get the touches began and then the touches ended points, with no points in between.
I was wondering if I could get better time (and space) resolution by using an NSTimer to query the touch object for its locationInView without waiting for it to call touchesmoved. Anyone knows if this might work?
Thanks.
I'll advise against NSTimer - its better to use CADisplayLink approach. For example, try to use my tiny lib https://github.com/nt9/NTLoop

Repeating NSTimer locks UI thread

First of all, I know there are a few other StackOverflow questions about this subject, but I have read them all and I still am confused about what to do for my situation. I'm probably missing something obvious here, if you could help clarify that would be much appreciated!
I have a app which is doing a lot of work to animate images within a view - mainly comprised of a number of images moving in straight lines for a second or two at a time. I considered at first making them all simple, once off animations using UIView animateWithDuration for the whole duration of the movement. But I found that didn't give me a lot of power to intercept the movement or stop it or check where it was up to, so I scrapped that. My new approach is to use an NSTimer, firing 20 times per second, doing incremental movements. This way I also can intervene (almost) instantly to change the animation or stop it or update a status label based on how far through it is, etc, etc.
First of all...there probably is a better way than this. Feel free to suggest something better!
Assuming this is acceptable though, my issue now is that while these animations are happening, I can't click any of the other controls on the UI. I get no response. It's not like it's just slow or delayed either - the click never comes through. It seems that the NSTimer processing totally locks the UI - but only from new interactions. Changes I make to the UI within the timer processing method happen just fine, and are very snappy.
From what I've read this shouldn't happen. However I also saw a comment on this question saying that if the timer processing is intensive then it could lock the UI thread. I don't see my processing to be that intensive here - certainly no resource requests, just a bit of data manipulating and animating some objects - but I could be underplaying it.
What are my options here? At first I thought I might create a new thread to kick off the timer. But I remember reading that the UI updates have to happen on the main thread anyway. Why is this? And plus, would that really solve the issue? Am I just asking too much of the device to process this timer as well as UI interactions? Is there something else I'm missing?
Any and all advice would be appreciated.
Edit:
I've just found the cause of my UI blocking problem. I was using the animateWithDuration with blocks, but was not setting the options. Therefore UIViewAnimationOptionAllowUserInteraction was not set. I changed it to set this option and my UI is happily responding now.
That said, I'll still leave this question open for specific suggestions regarding my overall approach. Thanks.
I would consider using CADisplayLink. From the documentation:
A CADisplayLink object is a timer object that allows your application to synchronize its drawing to the refresh rate of the display.
Your application creates a new display link, providing a target object and a selector to be called when the screen is updated. Next, your application adds the display link to a run loop.
Once the display link is associated with a run loop, the selector on the target is called when the screen’s contents need to be updated. The target can read the display link’s timestamp property to retrieve the time that the previous frame was displayed. For example, an application that displays movies might use the timestamp to calculate which video frame will be displayed next. An application that performs its own animations might use the timestamp to determine where and how displayed objects appear in the upcoming frame. The duration property provides the amount of time between frames. You can use this value in your application to calculate the frame rate of the display, the approximate time that the next frame will be displayed, and to adjust the drawing behavior so that the next frame is prepared in time to be displayed.
Your application can disable notifications by setting the paused property to YES. Also, if your application cannot provide frames in the time provided, you may want to choose a slower frame rate. An application with a slower but consistent frame rate appears smoother to the user than an application that skips frames. You can increase the time between frames (and decrease the apparent frame rate) by changing the frameInterval property.
When your application finishes with a display link, it should call invalidate to remove it from all run loops and to disassociate it from the target.
CADisplayLink should not be subclassed.
I'm not totally sure how everything is handled in your program, but you might want to just consider having one thread/timer that controls all of the objects and their movements. There's really no need to create a separate thread/timer for every single object, as that will easily cause problems.
You can just create a class for your moving items with some variables that contain information about their direction, speed, duration, etc, and then have a controlling thread/timer calculate and move the objects. You can then intervene onto the one main controller object instead of having to deal with many other objects.
I think you'll find that even if you optimize this, timer based animation like this is not going to perform well.
You might want to ask about the specific things that you think you couldn't do with CoreAnimation. If you solve those issues, you'll end up with a much better result than trying to roll your own.