2

My current code for the button is.

-(IBAction)playsnare;    
{
    CFBundleRef mainBundle = CFBundleGetMainBundle();
    CFURLRef soundfileURLRef;
    soundfileURLRef =CFBundleCopyResourceURL(mainBundle, (CFStringRef) @"snare", CFSTR ("wav"), NULL);
    UInt32 SoundID;
    AudioServicesCreateSystemSoundID(soundfileURLRef, &SoundID);
    AudioServicesPlaySystemSound(SoundID);
}

What can I add to this to make the button play when pressed and stop when not pressed.

iPatel
  • 46,010
  • 16
  • 115
  • 137

3 Answers3

4

Your implementation for playing audio samples does not allow for this. Because you are using AudioServicesPlaySystemSound from the AudioToolbox framework, there is no way to stop playback once the audio sample is triggered. You can only get a callback once it has finished playing.

This way of playing sounds has other limitations also (taken from the docs)

In addition, when you use the AudioServicesPlaySystemSound function:

Sounds play at the current system audio volume, with no programmatic volume control available

Sounds play immediately

Looping and stereo positioning are unavailable

Simultaneous playback is unavailable: You can play only one sound at a time

The sound is played locally on the device speakers; it does not use audio routing.

To have control over stopping the sound once triggered, you'll need to use another API. For a high level API try AVAudioPlayer class from AVFoundation framework. You will then be able to hook up events from a button such as touch down to start playing the sound, and also events such as touch up inside and touch drag outside to stop the sound playing.

You may or may not encounter performance issues depending on what else you're doing. For better performance (and a lot more writing of code) AudioUnits would be the preferred choice.

A short example using AVAudioPlayer class would be something like this-

The following code assumes a property of type AVAudioPlayer named loopPlayer that is initialised with a file called some_audio_loop_file.wav in a UIViewController sub-class.

yourViewController.h

@property (nonatomic, strong) AVAudioPlayer *loopPlayer;

yourViewController.m

// set up loopPlayer property in for example viewDidLoad
NSURL* audioFileURL = [[NSBundle mainBundle] URLForResource:@"some_audio_loop_file" withExtension:@"wav"];
self.loopPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:audioFileURL error:nil];

// called from a UIButton touch down event
-(IBAction)startAudioSample:(id)sender {
     [self.loopPlayer play];
}

// called from a UIButton touch up inside and touch drag outside events
-(IBAction)stopAudioSample:(id)sender {
     if (self.loopPlayer.isPlaying) {
          [self.loopPlayer stop];
          self.loopPlayer.currentTime = 0;
          self.loopPlayer.numberOfLoops = -1;
          [self.loopPlayer prepareToPlay];
}
Bamsworld
  • 5,670
  • 2
  • 32
  • 37
  • I know this may seem like a stupid questions however where would you add the name of the sound file and file type into that code? – Zach Chernicky Feb 08 '14 at 16:32
  • Please see my edit. I've added code that sets up the AVAudioPlayer with a file. – Bamsworld Feb 08 '14 at 16:47
  • I added all of that code and it basically does what I want, thank you! However is there a way to reset the audio sample back to the beginning every time the button is pressed? Currently every time I press it it just starts where it left off. – Zach Chernicky Feb 08 '14 at 17:00
  • Stopping the player does not reset the play head. To do this set the currentTime property to 0. I'll update the stopAudioSample: method in my answer. – Bamsworld Feb 08 '14 at 17:06
  • Your welcome. I suggest reading the AVAudioPlayer class ref and also have a look at AVAudioPlayerDelegate protocol ref for more info. – Bamsworld Feb 08 '14 at 17:12
1

Try:

-(IBAction)longPress:(UILongPressGestureRecognizer*)playsnare;    
{
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFURLRef soundfileURLRef;
soundfileURLRef =CFBundleCopyResourceURL(mainBundle, (CFStringRef) @"snare", CFSTR ("wav"), NULL);
UInt32 SoundID;
AudioServicesCreateSystemSoundID(soundfileURLRef, &SoundID);
AudioServicesPlaySystemSound(SoundID);
}

UILongPressGestureRecognizer is a continuous event recognizer. You have to look at the state to see if this is the start, middle or end of the event and act accordingly. i.e. you can through away all events after the start, or only look at movement as you need. From the Class Reference:

Long-press gestures are continuous. The gesture begins (UIGestureRecognizerStateBegan) when the number of allowable fingers (numberOfTouchesRequired) have been pressed for the specified period (minimumPressDuration) and the touches do not move beyond the allowable range of movement (allowableMovement). The gesture recognizer transitions to the Change state whenever a finger moves, and it ends (UIGestureRecognizerStateEnded) when any of the fingers are lifted.

Now You Can Track The State Like This

-  (void)handleLongPress:(UILongPressGestureRecognizer*)sender { 
        if (sender.state == UIGestureRecognizerStateEnded) {
           NSLog(@"UIGestureRecognizerStateEnded");
           //Do Whatever You want on End of Gesture
        }
       else if (sender.state == UIGestureRecognizerStateBegan){
           NSLog(@"UIGestureRecognizerStateBegan.");
          //Do Whatever You want on Began of Gesture
        }
  }

detail from: https://stackoverflow.com/a/3320351/1255945

Community
  • 1
  • 1
MarkP
  • 2,546
  • 5
  • 31
  • 48
  • I'm a little bit confused as I am fairly new to Xcode. What am I supposed to with the longpress: that shows up under received actions? Also am I supposed to add code under the back slashes to make the audio stop and play? – Zach Chernicky Feb 08 '14 at 07:17
-2

Create a property

bool isPlaying

and then as in your IBAction function

if(isPlaying){
  stop();
}else{
 play();
}
Eike
  • 2,311
  • 20
  • 31