2

I am trying to play a sound when a button it tapped and am using the iOS 5 file player audio unit.

The file player plays audio using the ScheduledAudioFileRegion and can be scheduled to play as many frames as needed

ScheduledAudioFileRegion rgn;
memset (&rgn.mTimeStamp, 0, sizeof(rgn.mTimeStamp));
rgn.mTimeStamp.mFlags = kAudioTimeStampSampleTimeValid;
rgn.mTimeStamp.mSampleTime = 0;
rgn.mCompletionProc = NULL;
rgn.mCompletionProcUserData = NULL;
rgn.mAudioFile = audioFile;
rgn.mLoopCount = INT_MAX;
rgn.mStartFrame = 0;
rgn.mFramesToPlay = nPackets * fileASBD.mFramesPerPacket; // plays entire file.

How can I tell this file player to play the sound from the start whenever a button is pressed, or do I have to create a new region and memset it each time? I would like the sound to play when the button is pressed from start to finish but when the button is tapped again, it should start from the beginning even if the file is currently playing. Is this possible with the fileplayer audio unit?

some_id
  • 29,466
  • 62
  • 182
  • 304
  • You don't need to use `INT_MAX` to get indefinite looping, setting `mLoopCount` to `-1` will cause the region to loop indefinitely. – j b Aug 14 '12 at 14:58
  • Is it the case that you *only* want a soundfile to play when a button is pressed, or do you want to do more than that e.g. trigger overlapping sound files, add effects etc? If it's just a simple trigger, it would be *much* more straightforward to use `AudioServicesPlaySystemSound` as described [here](http://stackoverflow.com/a/2778996/172218). AudioUnits are overkill for simple sound file triggering. – j b Aug 14 '12 at 15:08
  • I am using core-audio audio units to capture the sounds and create augraphs with subgraphs too. I need to capture these triggered sounds in the main mix. – some_id Aug 18 '12 at 13:18

2 Answers2

3

Call AudioUnitReset to stop playback, then prime and play again. Happens instantly (or as near as makes no difference.)

Do this whenever your user presses the button:

// Reset
AudioUnitReset(filePlayerUnit, kAudioUnitScope_Global, 0);
// Prime (have to do this before every play call.)
UInt32 defaultVal = 0;
AudioUnitSetProperty(filePlayerUnit, 
                     kAudioUnitProperty_ScheduledFilePrime,                
                     kAudioUnitScope_Global, 
                     0, 
                     &defaultVal, 
                     sizeof(defaultVal));
// Play (again)
AudioUnitSetProperty(_playerUnit,
                     kAudioUnitProperty_ScheduleStartTimeStamp,
                     kAudioUnitScope_Global,
                     0,
                     &startTime,
                     sizeof(startTime));

You already have your timestamps in the region. You need those, but you also have to create an AudioTimeStamp:

AudioTimeStamp startTime;
memset(&startTime, 0, sizeof(startTime));
startTime.mFlags = kAudioTimeStampSampleTimeValid;
startTime.mSampleTime = -1;

Create this, and call the associated SetProperty from the first snippet above, before you call play the first time.

Aran Mulholland
  • 23,555
  • 29
  • 141
  • 228
Tim
  • 5,024
  • 2
  • 30
  • 58
1

Can you not just have your UIButton trigger a Stop action before calls Play..?

Bonedog
  • 19
  • 2
  • 1
    Stop action on what if I may ask? I need maximum responsiveness without the redirection of code through a higher level framework.I am using core audio, for what I need Tim's answer works. – some_id Jan 04 '13 at 20:44