I'm making app using MPMoviePlayerController.
I want to make special function.
What I want to function is like this.
If I play movie, player will stop after few second (ex: 30sec).
If I click play button, player has to play from 30sec to next stop point.
For me to realize this function, I've used initialPlaybackTime and endPlaybackTime option of MPMoviePlayerContrller.
But, this function didn't work like my thought.
mplayer.initialPlaybackTime = 0;
mplayer.endPlaybackTime = 10;
[mplayer play];
....
[mplayer pause];
,,,
mplayer.initialPlaybackTime = 10;
mplayer.endPlaybackTime =30;
[mplayer play];
And, mplayer is played again from 0 to 10, not from 10 to 30.
This is a little late, but for anyone who comes upon this question, it appears that endplaybacktime and initialplayback time can only be set once for an initialized mpmovieplayercontroller. If you want to reset the values you'll have to destroy your mpmovieplayercontroller instance and create a new one.
This is very disappointing, could I be wrong? I would love it if I were.
Change your code to set the currentPlaybackTime before restarting the playback. Note, the order of initializing these properties does matter.
[...]
mplayer.initialPlaybackTime = 10.0;
mplayer.endPlaybackTime = 30.0;
mplayer.currentPlaybackTime = 10.0;
[mplayer play];
Related
I am new to sounds in Xcode and I wish to play a sound repeatedly, whether it is playing already or not. Eg. I have three lasers which are being shot, and I wish for the laser sound to be played three times simultaneously, without waiting for each one to finish playing. How do I achieve this using AVAudioPlayer?
Do this:
AVAudioPlayer *laserSound1 = .........
laserSound1.numberOfLoops = 2; //plays three times simultaneously
[laserSound1 play];
AVAudioPlayer *laserSound2 = .........
laserSound2.numberOfLoops = 2;//plays three times simultaneously
[laserSound2 play];
AVAudioPlayer *laserSound3 = .........
laserSound3.numberOfLoops = 2;//plays three times simultaneously
[laserSound3 play];
I play a MP3 in my iPhone app using AVAudioPlayer; i need to perform some operations at certain times (say 30th seconds, 1 minute); is there a way to invoke callback functions based on mp3 playing time?
I believe the best solution is to start an NSTimer as you start the AVAudioPlayer playing. You could set the timer to fire every half second or so. Then each time your timer fires, look at the currentTime property on your audio player.
In order to do something at certain intervals, I'd suggest you kept an instance variable for the playback time from last time your timer callback was called. Then if you had passed the critical point between last callback and this, do your action.
So, in pseudocode, the timer callback:
Get the currentTime of your AVAudioPlayer
Check to see if currentTime is greater than criticalPoint
If yes, check to see if lastCurrentTime is less than criticalPoint
If yes to that too, do your action.
Set lastCurrentTime to currentTime
If you're able to use AVPlayer instead of AVAudioPlayer, you can set boundary or periodic time observers:
// File URL or URL of a media library item
AVPlayer *player = [[AVPlayer alloc] initWithURL:url];
CMTime time = CMTimeMakeWithSeconds(30.0, 600);
NSArray *times = [NSArray arrayWithObject:[NSValue valueWithCMTime:time]];
id playerObserver = [player addBoundaryTimeObserverForTimes:times queue:NULL usingBlock:^{
NSLog(#"Playback time is 30 seconds");
}];
[player play];
// remove the observer when you're done with the player:
[player removeTimeObserver:playerObserver];
AVPlayer documentation:
http://developer.apple.com/library/ios/#documentation/AVFoundation/Reference/AVPlayer_Class/Reference/Reference.html
I found this link describing a property property which seems to indicate you can get the current playback time.
If the sound is playing, currentTime is the offset of the current
playback position, measured in seconds from the start of the sound. If
the sound is not playing, currentTime is the offset of where playing
starts upon calling the play method, measured in seconds from the
start of the sound.
By setting this property you can seek to a specific point in a sound
file or implement audio fast-forward and rewind functions.
To check the time and perform your action you can simply query it:
if (avAudioPlayerObject.currentTime == 30.0) //You may need a more broad check. Double may not be able to exactly represent 30.0s
{
//Do Something
}
with multithreading your goal is simple, just do like this :
1 : in your main thread create a variable for storing time passed
2 : create new thread like "checkthread" that check each 30-20 sec(as you need)
3 : if the time passed is what you want do the callback
Yes Sure you can ...it's tricky i hope it works for you but it works for me ..
1- you play your mp3 file.
2- [self performSelector:#selector(Operation:) withObject:Object afterDelay:30];
then the function
-(void)Operation:(id)sender;
called; so you fired function after 30 second of mp3 file .. you can make many of function based on time you want..
3- there is other solution using timers
[NSTimer scheduledTimerWithTimeInterval:0 target:self selector:#selector(CheckTime:) userInfo:nil repeats:YES];
it will fire function called Check Time
-(void)CheckTime:(id)sender{
if (avAudioPlayerObject.currentTime == 30.0)
{
//Do Something
//Fire and function call such
[self performSelector:#selector(Operation:) withObject:Object]
}
}
then you can change time interval you want and repeats is for you to control repeat this action every 5 seconds or not..
Hope that helpful..
Thanks
i think ,you want to play different sound-files after 30sec then use this code :
1) all sound-files put in Array and then retrieve from document directory
2)then try this:
-(IBAction)play_sound
{
BackgroundPlayer=[[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:[[NSBundle mainBundle]pathForResource:[Arr_tone_selected objectAtIndex:j]ofType:#"mp3"]]error:NULL];
BackgroundPlayer.delegate=self;
[BackgroundPlayer play];
}
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
[BackgroundPlayer stop];
j++;
[self performSelector:#selector(play_sound) withObject:Object afterDelay:30];
}
I have 2 views in my app, that are identical, they just load in a different array of sound files to use with their respective AVAudioPlayer.
However, ON THE DEVICE ONLY, on my second view, the sound seems to only play once after initialization, then it doesn't play until I initialize the player again.
This is my play button code:
- (IBAction)play:(id)sender {
if (((int)buttonCount % 2) == 0) {
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
self.audioPlayer.currentTime = 0;
self.audioPlayer.volume = volumeSlider.value;
[self.audioPlayer play];
[playButton setTitle:#"Stop..." forState:UIControlStateNormal];
buttonCount++;
[self fadePickerAnimation:NO];
NSLog(#"Should play");
}
else {
[self initializeSoundAfterStop:YES];
NSLog(#"Shouldn't play");
}
NSLog(#"buttoncount %i",buttonCount);
NSLog(#"What is the playing state? %i", self.audioPlayer.playing);
}
and the function it calls under the else clause:
- (void)initializeSoundAfterStop:(BOOL)addToButtonCount {
//Initialize audioPlayer once completely stopped
[self.audioPlayer stop];
[self.audioPlayer prepareToPlay];
[playButton setTitle:#"Chime!" forState:UIControlStateNormal];
if (addToButtonCount == YES) {
buttonCount++;
}}
The NSLogs in the above code output this as I continuously press the play button:
Should play
buttoncount 1
What is the playing state? 1
Shouldn't play
buttoncount 2
What is the playing state? 0
Should play
buttoncount 3
What is the playing state? 0
Shouldn't play
buttoncount 4
What is the playing state? 0
Should play
buttoncount 5
What is the playing state? 0
Shouldn't play
buttoncount 6
What is the playing state? 0
So as you can see, it gets stuck in a non-playing mode for some reason.
This method is used in exactly the same fashion in my first view, and it works without any problem. And it all works fine on the simulator, just not on my iPhone 4. Cannot figure this out. The play method of audioPlayer gets called when I setup a breakpoint, so I dunno!
Thanks!
Couldn't find out why this was happening, however, I fixed it by simply adding in my AVAdioPlayer initializer function at the top of the play IBAction.
Might not be the most graceful solution, but it works.
Just beware of memory allocation if you decide to do this.
I have a drum app that I've created basing it off of AVAudioPlayer instead of the common system sounds in order to have a bit of control.
The problem is that whenever two or more sounds are played at once, it lags and stops alls sounds, so your drum beat gets choppy and randomly stopped.
For example: boom boom chhhhh boom boom ch--- boom bo---- chhhhh
If you can tell at all from that onomatopoeia.
Here's the sound code, I have an array of preloaded AVAudioPlayer so that it loads faster.
- (void)triggerSound:(NSInteger)soundNumber {
NSInteger deltaNum = soundNumber*numberOfBuffers;
AVAudioPlayer *lowBuffer = [bufferBox objectAtIndex:deltaNum];
Boolean soundFired = FALSE;
// Find an unused buffer if possible, otherwise play sound from first buffer.
for (int i=0; i<numberOfBuffers; i++) {
NSLog(#"Buffer loop: %d", i);
NSLog(#"Buffer to load: %d", deltaNum);
AVAudioPlayer *tempBuffer = [bufferBox objectAtIndex:deltaNum+i];
if (!tempBuffer.playing) {
tempBuffer.currentTime = 0;
[tempBuffer play];
soundFired = TRUE;
break;
} else if (lowBuffer.currentTime>tempBuffer.currentTime) {
lowBuffer = tempBuffer;
}
}
if (!soundFired) {
lowBuffer.currentTime = 0;
[lowBuffer play];
soundFired = TRUE;
}
}
That method is called in the IBAction button press. ex: [drumObject triggerSound:3].
All help appreciated!
I've had much better experiences with the OpenAL API for some games. It is very different and more low level (you have to deal with sources and buffers) but it worked much better for me than AVAudioPlayer.
You could try using an iOS game engine for your audio needs.
For example: http://gamua.com/sparrow/
You don't actually have to use the graphics part of this engine. Just import and use the audio part of the framework (which provides a simple API on top of OpenAL).
I'm using OpenAL sound framework on the iPhone, and I'm setting different volumes on individual sounds. I'm running into a problem where I'm hearing an initial popping/clicking noise when switching from one sound to the next.
It's really noticeable when I have one sound that's got a high volume (1.0) and a second
sound that has a low one (0.2). When I hit the loud sound, and then
hit the soft sound, I hear the pop/click. But when I go from the soft
sound to the loud, I don't notice anything. So the pop/click really
happens when switching from loud to soft sounds.
Here's the init sound method:
- (id) initWithSoundFile:(NSString *)file doesLoop:(BOOL)loops
{
self = [super init];
if (self != nil)
{
if(![self loadSoundFile:file doesLoop:loops])
{
debug(#"Failed to load the sound file: %#...", file);
[self release];
return nil;
}
self.sourceFileName = file;
//temporary sound queue
self.temporarySounds = [NSMutableArray array];
//default volume/pitch
self.volume = 1.0;
self.pitch = 1.0;
}
return self;
}
and here's the play function:
- (BOOL) play
{
if([self isPlaying]) //see if the base source is busy...
{
//if so, create a new source
NSUInteger tmpSourceID;
alGenSources(1, &tmpSourceID);
//attach the buffer to the source
alSourcei(tmpSourceID, AL_BUFFER, bufferID);
alSourcePlay(tmpSourceID);
//add the sound id to the play queue so we can dispose of it later
[temporarySounds addObject: [NSNumber numberWithUnsignedInteger:tmpSourceID]];
//a "callback" for when the sound is done playing +0.1 secs
[self performSelector:#selector(deleteTemporarySource)
withObject:nil
afterDelay:(duration * pitch) + 0.1];
return ((error = alGetError()) != AL_NO_ERROR);
}
//if the base source isn't busy, just use that one...
alSourcePlay(sourceID);
return ((error = alGetError()) != AL_NO_ERROR);
}
and here's the function where i set the volume for each sound immediately after playing (ive tried setting it before playing too):
- (void) setVolume:(ALfloat)newVolume
{
volume = MAX(MIN(newVolume, 1.0f), 0.0f); //cap to 0-1
alSourcef(sourceID, AL_GAIN, volume);
//now set the volume for any temporary sounds...
for(NSNumber *tmpSourceID in temporarySounds)
{
//tmpSourceID is the source ID for the temporary sound
alSourcef([tmpSourceID unsignedIntegerValue], AL_GAIN, volume);
}
}
Any help is greatly appreciated as I've tried everything I can think of. I would be so grateful.
All I had to do was use calloc instead of malloc to allocate memory for the OpenAL buffer.
Or you could also zero set the memory with memset.
The wierd popping noise went off. It was due to junk memory in my case. That's why it was random too. Hope this helps.
This problem is caused by not calling alSourceStop.
The documentation doesn't really state this, but alSourceStop must be called on a sound source before it can be reused even if the sound had already finished and the AL_SOURCE_STATE parameter of the source is not AL_PLAYING.
I've randomly got to this unaswered question and, finding that the problem was not solved, I'll try to give my answer, even if a long time has passed.
I don't know OpenAL, but it sounds like this is a purely audio problem. It is normal to hear short clicks when you change suddenly the level of the audio, especially from a high value to a low value. For example, if you map directly the volume of the audio to a slider, which value is updated every few ms, you can easily hear clicks and pops when sliding fast the control. What audio software developers do is smoothing the parameter changes with a low pass filter.
In your case, I would suggest you to stop the clip after fading it out, and start a new clip by fading it in. The fade time can be as short as 2 ms: it's not audible, and the sound will play just finely.
I wonder if (some versions of) OpenAL can automatically deal with this issue.