Question

Is there a way to programmatically invoke the keypad "click" sound? My app has a custom keypad (built out of UIButtons) and I'd like to provide some audio feedback when the user taps on the keys. I tried creating my own sounds in Garageband, but wasn't happy with any of my creations. If there isn't a standard way to invoke the key click, can anyone point me to a library of sounds that might have such a gem?

Was it helpful?

Solution

The simplest way I've found is to extract Tock.aiff (the keyboard sound) from the iPhone Simulator and package it with your app, then play it using AudioServicesPlaySystemSound() at the appropriate time. On my machine, simply typing Tock.aiff into Spotlight turns up the file, but if you have to go looking for it, it's in the simulator version of UIKit.framework.

OTHER TIPS

There is a really fast solution to play the default keyboard sound:

  1. Add AudioToolbox.framework
  2. Add the following line wherever you want the sound to play:

    AudioServicesPlaySystemSound(0x450);

As of iOS 4.2, adopt the UIInputViewAudioFeedback protocol on a custom subclass of UIView. Make this view your "inputView" and then call "playInputClick" at the appropriate time.

http://developer.apple.com/library/ios/#documentation/uikit/reference/UIInputViewAudioFeedback_ProtocolReference/Reference/Reference.html

Just to save some people time. Put this in your custom view:

- (BOOL) enableInputClicksWhenVisible {
    return YES;
}

To make the click do this:

[[UIDevice currentDevice] playInputClick];

No need to copy the file into your own app - you should be able to get it directly from the UIKit framework:

CFURLRef soundFileURLRef = CFBundleCopyResourceURL(
    CFBundleGetBundleWithIdentifier(CFSTR("com.apple.UIKit")),
    CFSTR ("Tock"),CFSTR ("aiff"),NULL);

This is what I made out of it aSquared's comment:

NSString *path = [[NSBundle bundleWithIdentifier:@"com.apple.UIKit"] pathForResource:@"Tock" ofType:@"aiff"];
SystemSoundID soundID;
AudioServicesCreateSystemSoundID((CFURLRef)[NSURL fileURLWithPath:path], &soundID);
AudioServicesPlaySystemSound(soundID);
AudioServicesDisposeSystemSoundID(soundID);

Using 0x450 as the SystemSoundID works for me (and at the correct volume - just playing the built-in Tock.aiff was too loud). No idea how portable that is - this is on an iPod Touch 3rd gen.

Still doesn't respect the preference for tick on/off.

Here's what I did:

Locate 'Tock.aiff' in: /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.2.sdk/System/Library/Frameworks/UIKit.framework

Drag it into your Resources folder in xCode, ticking 'Copy items into destination group's folder'

Import AVFoundation.framework into the Frameworks folder in xCode

Import AVFoundation at the top of your class:

#import <AVFoundation/AVAudioPlayer.h>

Use the following function:

- (void)PlayClick {
    NSURL* musicFile = [NSURL fileURLWithPath:[[NSBundle mainBundle] 
                                               pathForResource:@"Tock"
                                               ofType:@"aiff"]];
    AVAudioPlayer *click = [[AVAudioPlayer alloc] initWithContentsOfURL:musicFile error:nil];
    [click setVolume:0.15f];
    [click play];
}

That's it!

From what I can tell, the click sound isn't available to apps. I haven't seen anything in audio session services that is relevant. AudioServicesPlaySystemSound() looks promising, but there doesn't appear to be any system sound ID for the click sound (a closer look at the headers may turn up something). You could always loop over a call to AudioServicesPlaySystemSound(i) and see if anything plays. The iPhone software restore images probably have the sound, but it's probably not licensed for general use. Jailbreaking an iPhone to get at the tasty click sound doesn't need to be mentioned.

For (creative commons) sounds, check out the Freesound Project.

For the future, perhaps request that Apple expose system sounds other than the alert sound for use with AudioServicesPlaySystemSound().

Maybe a bit late ... But in MrMage last post, if you do AudioServicesDisposeSystemSoundID(soundID); straight after AudioServicesPlaySystemSound(soundID); then you won't hear a thing as you're discarding the system sound right after creating it.

You have to let it finish playing first.. Only call AudioServicesDisposeSystemSoundID to cancel the sound before it finishes

You do not have to dispose of the sound object right away. Keep a pointer to that sound object in a property, and dispose of it only when you are about to play another sound before re-creating it.

And of course finally dispose of the SystemSoundID object in dealloc.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top