Advertise here




Advertise here

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Generate a Beep / Tone / DTMF

DutchDutch Posts: 884Registered Users
edited March 2010 in iOS SDK Development
I am wondering if anyone has come across a way to generate tones in the iPhone SDK. I am trying to generate DTMF tones, and can't seem to find anything substantial out there. I want to be able to specify how long to play the tone for as well.

I found an open source app called iPhreak. It supposedly generates DTMF tones to fool payphones (I Assure you this is not my intention - my company deals with telephone based intercom systems). The only problem with that application is that there are files missing from the open source project. Perhaps someone else can get this project to work?
Post edited by Dutch on
«1

Replies

  • DutchDutch Posts: 884Registered Users
    edited September 2009
    Just a friendly bump - Does anyone know how to generate DTMF tones?
  • nobre84nobre84 Posts: 981Registered Users @ @ @
    edited September 2009
    The Tone itself is just a mix of two frequencies, so you need a signal generator and a way to play your frequencies...
    That project seems outdated regarding the "playing" part of the puzzle... But it has a simple frequency based sample generator in the Tone class (inside TonePlayer.h/m)

    Take a look in the current apple docs about how to enque an in memory audio buffer and try to play the tones generated from your class.. Good luck !


    http://developer.apple.com/IPhone/library/documentation/MusicAudio/Conceptual/AudioQueueProgrammingGuide/AQPlayback/PlayingAudio.html#//apple_ref/doc/uid/TP40005343-CH3-SW1
  • DutchDutch Posts: 884Registered Users
    edited September 2009
    that link doesnt work for me.... Let me browse around...
  • DutchDutch Posts: 884Registered Users
    edited September 2009
    I got this answer on stackOverflow.. sounds like the same thing you're saying...
    hi,

    should be easy enough to generate yourself. given that the hardware can playback a pcm buffer (16bit samples) at 44.1 khz (which it surely can with some library function or the other), you're only left with calculating the waveform:
    const int PLAYBACKFREQ = 44100;
     const float PI2 = 3.14159265359f * 2;
    
     void generateDTMF(short *buffer, int length, float freq1, float freq2)
     {
          int i;
          short *dest = buffer;
          for(i=0; i<length; i++)
          {
               *(dest++) = (sin(i*(PI2*(PLAYBACKFREQ/freq1))) + sin(i*(PI2*(PLAYBACKFREQ/freq2)))) * 16383;
          }
     }
    
    the 16383 is done since I'm using additive synthesis (just adding the sinewaves together). Therefore the max result is -2.0 - 2.0 So after multiplying by 16383 I get more or less the max 16 bit result: -32768 - +32767

    EDIT: the 2 frequenties are the frequenties from the wikipedia article the other person who answered linked to (http://en.wikipedia.org/wiki/Dual-tone_multi-frequency#Keypad). Two unique frequencies make a DTMF sound

    you create a buffer of sufficient length of a 16 bit signed datatype (I'm not sure how this is done in objective c). You then pick the 2 frequencies belonging to the dtmf tone of 3 (697hz and 1477hz). Call my function with a pointer to the buffer, the length you allocated and then the function will fill it with the waveform of the DTMF tone. This Waveform you'll then have to pass to the iPhone library function which can output the contents of a buffer to the audiohardware.

    Note that the buffer is rendered with 44100 samples/seq. So when playing the waveform, the audio hardware should use the same frequenty or else the DTMF frequencies will be off. Also note, that if you want the waveform to last 10 seconds, then the buffer length should be PLAYBACKFREQ*10. I hope this explains it a bit. More info on PCM (the way a waveform is stored in computer memory) can be found here: Pulse-code modulation - Wikipedia, the free encyclopedia

    I have no idea where to start so I will hit the Docs hard. If anyone has any pointers, I am all ears!! Thanks Nobre
  • nobre84nobre84 Posts: 981Registered Users @ @ @
    edited September 2009
    I fixed the link, its about audio queue services, looks like it shows the steps to read a file from disk into a samples buffer and then enqueue it to play. You should be able to fill a similar buffer with your sample generator
  • DutchDutch Posts: 884Registered Users
    edited September 2009
    I think I found some open source code that appears to be what you are recommending, however I get all sorts of errors...

    THIS IS THE FULL PROJECT: Source Checkout - itone - Project Hosting on Google Code

    It seems there may be a problem with my CoreAudio framework? I did try an SDK reinstall but nothing has changed...
    error: expected specifier-qualifier-list before 'AudioDeviceID'
    error: expected specifier-qualifier-list before 'AudioStreamBasicDescription'
    error: expected '=', ',', ';', 'asm' or '__attribute__' before 'GetDefaultOutputDevice'
    error: expected '=', ',', ';', 'asm' or '__attribute__' before 'GetStreamForDevice'
    error: expected '=', ',', ';', 'asm' or '__attribute__' before 'GetDefaultOutputStream'
    error: expected ')' before 'stream_id'
    error: expected ')' before 'inDevice'
    error: 'device' undeclared (first use in this function)


    .h file
    //
    //  TonePlayer.h
    //  iTone
    //
    //  Created by Allen Porter on 4/20/08.
    //  Copyright 2008 __MyCompanyName__. All rights reserved.
    //
    
    [COLOR="Green"]//had to comment this out to surpress errors.
    //#import <CoreAudio/CoreAudio.h>[/COLOR]
    
    enum Mode {
        SIN = 0,
        SQUARE,
        SAWTOOTH,
        TRIANGLE,
        THEREMIN,
    };
    
    @interface TonePlayer : NSObject {
        int sample;
        int frequency;
        int mode;
        AudioDeviceID device;
        AudioStreamBasicDescription description;
    }
    
    - (id) init;
    
    @property(readwrite) int mode;
    @property(readwrite) int frequency;
    @property(readwrite) int sample;
    
    - (BOOL) start;
    - (BOOL) stop;
    @end
    

    .m file
    //
    //  TonePlayer.m
    //  iTone
    //
    //  Created by Allen Porter on 4/20/08.
    //  Copyright 2008 __MyCompanyName__. All rights reserved.
    //
    
    #import "TonePlayer.h"
    
    #define PI 3.14159265
    
    AudioDeviceID GetDefaultOutputDevice() {
        AudioDeviceID device;
        UInt32 size = sizeof(AudioDeviceID);
        OSStatus ret;
        ret = AudioHardwareGetProperty(kAudioHardwarePropertyDefaultOutputDevice,
                                       &size,
                                       &device);
        assert(ret == 0);
        return device;
    }
    
    AudioStreamID GetStreamForDevice(AudioDeviceID device, bool input) {
        OSStatus ret;
        UInt32 size;
        ret = AudioDeviceGetPropertyInfo(device,
                                         0,
                                         input,
                                         kAudioDevicePropertyStreams,
                                         &size,
                                         NULL);
        assert(ret == 0);
        assert(size > 0);
        int num_streams = size / sizeof(AudioStreamID);
        AudioStreamID* streams = (AudioStreamID*)malloc(num_streams * sizeof(AudioStreamID));
        ret = AudioDeviceGetProperty(device,
                                     0,
                                     input,
                                     kAudioDevicePropertyStreams,
                                     &size,
                                     streams);
        AudioStreamID stream = streams[0];
        free(streams);
        return stream;
    }
    
    AudioStreamID GetDefaultOutputStream() {
        return GetStreamForDevice(GetDefaultOutputDevice(), false);
    }
    
    bool GetStreamDescription(AudioStreamID stream_id,
                              AudioStreamBasicDescription* description) {
        OSStatus ret;
        UInt32 size = sizeof(AudioStreamBasicDescription);;
        ret = AudioStreamGetProperty(stream_id,
                                     0,
                                     kAudioStreamPropertyPhysicalFormat,
                                     &size,
                                     description);
        return (ret == 0);
    }
    
    OSStatus Proc(AudioDeviceID inDevice,
                  const AudioTimeStamp* inNow,
                  const AudioBufferList* inInputData,
                  const AudioTimeStamp* inInputTime,
                  AudioBufferList* outOutputData,
                  const AudioTimeStamp* inOutputTime,
                  void* inClientData) {
        assert(outOutputData->mNumberBuffers > 0);
        assert(inOutputTime->mSampleTime != 0);
        
        TonePlayer* state = (TonePlayer*)inClientData;
        
        AudioBuffer* buf = &outOutputData->mBuffers[0];
        int units = buf->mDataByteSize / sizeof(float);
        float* data = (float*)buf->mData;
        float m = 2 / state->description.mSampleRate;
        for (int i = 0; i < units; ++i) {
            [state setSample:(([state sample] + 1) % (int)state->description.mSampleRate)];
            int t = [state sample];
            if ([state mode] == SAWTOOTH) {
                // TODO(allen): This doesn't work
                data[i] = m * t - 1.0;
            } else {
                // TODO(allen): Don't use the inefficient trig functions!
                data[i] = sinf((2 * PI * [state frequency] * t) / state->description.mSampleRate);
                switch ([state mode]) {
                    case SQUARE:
                        if (data[i] > 0) {
                            data[i] = 1;
                        } else if (data[i] < 0) {
                            data[i] = -1;
                        } 
                        break;
                    case THEREMIN:
                        if (data[i] < 0) {
                            data[i] = 0 - data[i];
                        }
                        break;
                }
            }
        }
        return 0;
    }
    
    @implementation TonePlayer
    
    @synthesize frequency;
    @synthesize sample;
    @synthesize mode;
    
    - (id) init
    {
        self = [super init];
        if (self != nil) {
            sample = 0;
            mode = SIN;
            frequency = 500;
            device = GetDefaultOutputDevice();
            if (!GetStreamDescription(GetDefaultOutputStream(), &description)) {
                return nil;
            }
            OSStatus status = AudioDeviceAddIOProc(device, &Proc, self);
            if (status) {
                NSLog(@"AudioDeviceAddIOProc failed: %lld (%s)");
                return nil;
            }
            
        }
        return self;
    }
    
    - (BOOL) start
    {
        NSLog(@"Starting w/ Frequency=%d", frequency);
        OSStatus status = AudioDeviceStart(device, &Proc);
        if (status) {
            NSLog(@"AudioDeviceStart failed: %lld", status);
            return NO;
        }
        return YES;
    }
    
    - (BOOL) stop
    {
        OSStatus status = AudioDeviceStop(device, &Proc);
        if (status) {
            NSLog(@"AudioDeviceStop failed: %lld (%s)", status);
            return NO;
        }
        return YES;
    }
    
    @end
    
    
  • nobre84nobre84 Posts: 981Registered Users @ @ @
    edited September 2009
    The snippet you posted earlier from stack overflow should do the trick to create your buffer.
    To play it , look the link I posted earlier, some more info on audio queues here :
    Audio Queue Services Programming Guide: About Audio Queues
  • DutchDutch Posts: 884Registered Users
    edited September 2009
    Perhaps (or most certainly) I am not initializing the buffer properly... This is what I am doing...
    -(IBAction)playTone:(id)sender{
    	iPhoneTonesAppDelegate *mainDelegate = (iPhoneTonesAppDelegate *)[[UIApplication sharedApplication] delegate];
    
    	signed short int *audioBuffer;  
    	[mainDelegate generateToneWithBuffer:audioBuffer forLength:1000 withFreq1:1209 withFreq2:697];
    
    	
    }
    
    const int PLAYBACKFREQ = 44100;
    const float PI2 = 3.14159265359f * 2;
    
    -(void) generateToneWithBuffer:(short *)buffer forLength:(int) length withFreq1:(float)freq1 withFreq2:(float)freq2{
    
    	short *dest = buffer;
    	for(int i=0; i<length; i++)
    		[COLOR="Red"]*(dest++) = (sin(i*(PI2*(PLAYBACKFREQ/freq1))) + sin(i* (PI2*(PLAYBACKFREQ/freq2)))) * 16383;[/COLOR]
    	
    }
    

    the line in red gives me a memory error...I'm afraid I don't understand whats happening here enough to figure out the problem... still reasearching...
  • DutchDutch Posts: 884Registered Users
    edited September 2009
    Also, things like AudioQueueBuffer are not usable because I think there is something wrong with my coreaudio.h file..
  • nobre84nobre84 Posts: 981Registered Users @ @ @
    edited September 2009
    You must allocate sizeof(signed short int)*length bytes to your *buffer , then the function can traverse it and populate the samples without throwing errors
    I never worked with the audioqueuebuffer and can't give you accurate insight , did you find the correct libraries/headers to add in the project ?
  • DutchDutch Posts: 884Registered Users
    edited September 2009
    nobre84 wrote: »
    You must allocate sizeof(signed short int)*length bytes to your *buffer , then the function can traverse it and populate the samples without throwing errors
    I never worked with the audioqueuebuffer and can't give you accurate insight , did you find the correct libraries/headers to add in the project ?

    IDK - I added CoreAudio.FrameWork, however all kinds of errors, still.. Still debugging... Thanks!!
  • nobre84nobre84 Posts: 981Registered Users @ @ @
    edited September 2009
    Did you make it work ? I'd like to see the outcome
  • DutchDutch Posts: 884Registered Users
    edited September 2009
    Unfortunately, no. Due to my lack of ability to get CoreAudio to work out, I have chosen to try a new direction in a desperate grab to get something functional... using the AVAudioPlayer.

    I would LOVE to use CoreAudio, if I could just get it working.. I would be happy to share the code if anyone would be willing to check it out. Its really just 16 buttons on a view .. nothing too valuable just yet.

    This is the crux of it...
    -(void) generateToneForLength:(int)length withFreq1:(float)freq1 withFreq2:(float)freq2{
    	
        NSLog(@"Attempting to play frequency %f + %f",freq1,freq2);
    	
        if (audioPlayer!=nil){
            [audioPlayer stop];
            [audioPlayer release];
            audioPlayer = nil;
        }
    
        [COLOR="Green"]//I *BELIEVE* this is working. Not sure yet, but no crashes.[/COLOR]
        short *dest =malloc(sizeof(length));  
        for(int i=0; i<length; i++)
            *(dest++) = (sin(i*(PI2*(PLAYBACKFREQ/freq1))) + sin(i* (PI2*(PLAYBACKFREQ/freq2)))) * 16383;
    
    [COLOR="Green"]    //This is the bit I am struggling with now...converting the short array 
        //into data, or some other object I can pass to the audio player.[/COLOR]
        NSData *d=[NSData dataWithBytes:dest length:length];
    
        NSError *playerSetupError = nil;
        audioPlayer = [[AVAudioPlayer alloc] initWithData:d error:&playerSetupError];
    
        if (playerSetupError) {
            UIAlertView *cantPlayAlert = [[UIAlertView alloc] initWithTitle: @"Cannot Play" message: [playerSetupError localizedDescription] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
            [cantPlayAlert show];
            [cantPlayAlert release]; 
            audioPlayer = nil;
        } else {
            audioPlayer.delegate = self;
            [audioPlayer prepareToPlay];
            [audioPlayer play];
            [COLOR="Green"]//audioPlayer.meteringEnabled = YES;[/COLOR]
    }
    
  • nobre84nobre84 Posts: 981Registered Users @ @ @
    edited September 2009
    the array still needs a little tweak,
    	/* number of samples per second * seconds to play */
    	int samplesLength = length * PLAYBACKFREQ;
        //I *BELIEVE* this is working. Not sure yet, but no crashes.
        short *dest =malloc(sizeof(short)*samplesLength);  
        for(int i=0; i<length; i++)
            *(dest++) = (sin(i*(PI2*(PLAYBACKFREQ/freq1))) + sin(i* (PI2*(PLAYBACKFREQ/freq2)))) * 16383;
    

    I don't think AVAudioPlayer expects a raw sample sequence though, you should study how to create a pcm or otherwise playable format out of that
  • DutchDutch Posts: 884Registered Users
    edited September 2009
    Would I be pushing my luck if I asked you to assist me in getting the CoreAudio working?
  • nobre84nobre84 Posts: 981Registered Users @ @ @
    edited September 2009
    I'm at work now, when I get home I can try to look into something
    I found a working project that uses AVAudioPlayer to play an mp3 file, maybe it has something useful:
    http://www.zdziarski.com/AVMeter.zip
  • tealeafxtealeafx Posts: 26Registered Users
    edited September 2009
    Here is a small working project that uses a custom AudioUnit with CoreAudio. It's cobbled together from various posts on the web. I don't have the original links but Google will probably help there. Compiles and runs under 2.2.1 - hope it helps.

    http://www.ideasunplugged.com/stuff/AudioIOUnitOutput.zip
    App: <a href="http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=317243351&mt=8"; target="_blank">Email Signature Pro</a> - <b>Personalize Your iPhone Email Signatures</b><br />
    App: <a href="http://phobos.apple.com/WebObjects/MZStore.w
  • DutchDutch Posts: 884Registered Users
    edited September 2009
    Wow - this is really nice. Now I just have to figure out how to mix two frequencies together - as this seems to only use one.

    I guess the question is, how do I implement my loop..
    -(void) generateToneForLength:(int)length withFreq1:(float)freq1 withFreq2:(float)freq2{
    
        int samplesLength = length * PLAYBACKFREQ;
        short *dest =malloc(sizeof(short)*samplesLength); 
        for(int i=0; i<length; i++)
            *(dest++) = (
                         sin(i*(PI2*(PLAYBACKFREQ/[COLOR="Red"][B]freq1[/B][/COLOR]))) + 
                         sin(i*(PI2*(PLAYBACKFREQ/[COLOR="Red"][B]freq2[/B][/COLOR])))
                         ) * 16383;
    }
    

    Into this bad boy in order to allow it to handle two frequencies....
    void generateTone(
                    vector<int>& pcm,
                    int [COLOR="Red"][B]freq[/B][/COLOR],
                    double lengthMS,
                    int sampleRate,
                    double riseTimeMS,
                    double gain)
    {
      int numSamples = ((double) sampleRate) * lengthMS / 1000.;
      int riseTimeSamples = ((double) sampleRate) * riseTimeMS / 1000.;
    
      if(gain > 1.)
        gain = 1.;
      if(gain < 0.)
        gain = 0.;
    
      pcm.resize(numSamples);
    
      for(int i = 0; i < numSamples; ++i)
      {
        double x = 2. * M_PI * [COLOR="Red"][B]freq[/B][/COLOR] * i / sampleRate;
        double value = sin(x) + sin(2. * x) / 2  + sin(4. * x) / 4;
        if(i < riseTimeSamples)
          value *= sin(i * M_PI / (2.0 * riseTimeSamples));
        if(i > numSamples - riseTimeSamples - 1)
          value *= sin(2. * M_PI * (i - (numSamples - riseTimeSamples) + riseTimeSamples)/ (4. * riseTimeSamples));
    
        pcm[i] = (int) (value * 32500.0 * gain);
        pcm[i] += (pcm[i]<<16);
      }
    }
    

    I don't really understand this in its entirety yet... but I will play around with it until I get it I suppose - what else can one do :)

    Thanks for the nod!
  • nobre84nobre84 Posts: 981Registered Users @ @ @
    edited September 2009
    The code above
    double value = sin(x) + sin(2. * x) / 2  + sin(4. * x) / 4;
    
    Simply mix the base frequency together with the first 2 upper harmonics (if you pass 440Hz in, it will mix 440 + 880 (at half volume) + 1760 (at 1/4 volume)
    You just need to pass in your 2 frequencies and add them up at half volume:
    double x = 2. * M_PI * 697 * i / sampleRate;
    	double x2 = 2. * M_PI * 1336 * i / sampleRate;
    	  double value = (sin(x) + sin(x2))/2; //+ sin(2. * x) / 2  + sin(4. * x) / 4;
    
    That gave me the DTMF for key 2 on a phone successfully!
  • nobre84nobre84 Posts: 981Registered Users @ @ @
    edited September 2009
    PS: Of course you can pre-calculate the sinus coefficients in a array or arrange a way of cycling through the waves instead of generating all of the samples on the fly, I don't how much load that can make on the device, you should test it carefully to optimize
  • tealeafxtealeafx Posts: 26Registered Users
    edited September 2009
    nobre84 wrote: »
    The code above
    double value = sin(x) + sin(2. * x) / 2  + sin(4. * x) / 4;
    

    What nobre84 said.
    App: <a href="http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=317243351&mt=8"; target="_blank">Email Signature Pro</a> - <b>Personalize Your iPhone Email Signatures</b><br />
    App: <a href="http://phobos.apple.com/WebObjects/MZStore.w
  • DutchDutch Posts: 884Registered Users
    edited September 2009
    Lol - will have to try this on monday. Had a road call that kept me out of the office 10A-6P. Blah!
  • DutchDutch Posts: 884Registered Users
    edited September 2009
    OK - I have this working semi-successfully thanks to you. I took your advice, and pre-loaded 16 separate instances of the TONER class, initializing each with its own frequencies and lengths. However it seems there are 2 problems now.

    1) There is a long pause after calling [toner start]. It seems the lag comes from the actual playing and not the intializing

    2) Only the first tone works - the rest are never played...I assume this has something to do with the [Toner initAudio] method. Perhaps I can't do 16 individual instances as such.

    Toner.M
    -(void)initWithFrequencies:(NSInteger)freq1 andThen:(NSInteger)freq2 forLength:(CGFloat)length{
        //generate pcm tone  freq = 440, duration = 1s, rise/fall time = 50ms, gain 0.8
        [self setFrq1:freq1];
        [self setFrq2:freq2];
    	
        generateTone(_pcm, freq1, freq2, length, SAMPLE_RATE, 100, 0.8);
        [self initAudio];
    }
    
    -(void)initAudio {
        _index = 0;
        OSStatus status;
        AudioComponentDescription desc;
        desc.componentType = kAudioUnitType_Output;
        desc.componentSubType = kAudioUnitSubType_RemoteIO;
        desc.componentFlags = 0;
        desc.componentFlagsMask = 0;
        desc.componentManufacturer = kAudioUnitManufacturer_Apple;
        
        // Get component
        AudioComponent inputComponent = AudioComponentFindNext(NULL, &desc);
        
        // Get audio units
        status = AudioComponentInstanceNew(inputComponent, &audioUnit);
        //checkStatus(status);
        
        UInt32 flag = 1;
        // Enable IO for playback
        status = AudioUnitSetProperty(audioUnit,
                    kAudioOutputUnitProperty_EnableIO,
                    kAudioUnitScope_Output,
                    kOutputBus,
                    &flag,
                    sizeof(flag));
    
        //checkStatus(status);
    
        AudioStreamBasicDescription audioFormat;
        audioFormat.mSampleRate = SAMPLE_RATE;
        audioFormat.mFormatID	= kAudioFormatLinearPCM;
        audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
        audioFormat.mFramesPerPacket = 1;
        audioFormat.mChannelsPerFrame = 2;
        audioFormat.mBitsPerChannel = 16;
        audioFormat.mBytesPerPacket = 4;
        audioFormat.mBytesPerFrame = 4;
        status = AudioUnitSetProperty(audioUnit,
                    kAudioUnitProperty_StreamFormat,
                    kAudioUnitScope_Input,
                    kOutputBus,
                    &audioFormat,
                    sizeof(audioFormat));
        //  checkStatus(status);
    
        AURenderCallbackStruct callbackStruct;
        callbackStruct.inputProc = playbackCallback;
        callbackStruct.inputProcRefCon = self;
        status = AudioUnitSetProperty(audioUnit,
                    kAudioUnitProperty_SetRenderCallback,
                    kAudioUnitScope_Global,
                    kOutputBus,
                    &callbackStruct,
                    sizeof(callbackStruct));
    
        status = AudioUnitInitialize(audioUnit);
    }
    
    -(void)start {
        OSStatus status;
        status = AudioOutputUnitStart(audioUnit);
    }
    


    mainViewController
    - (void)viewDidLoad {
        [super viewDidLoad];
        toners=[[NSMutableArray alloc]init];
    	
    
        Toner *t=[[Toner alloc] init];
        [t initWithFrequencies:1209 andThen:697 forLength:150]; //1
        [toners addObject:t];
        [t release], t=nil;
    	
        t=[[Toner alloc] init];
        [t initWithFrequencies:1336 andThen:697 forLength:150]; //2
        [toners addObject:t];
        [t release], t=nil;	
     
        t=[[Toner alloc] init];
        [t initWithFrequencies:1477 andThen:697 forLength:150]; //3
        [toners addObject:t];
        [t release], t=nil;	
    	
        t=[[Toner alloc] init];
        [t initWithFrequencies:1633 andThen:697 forLength:150]; //A
        [toners addObject:t];
        [t release], t=nil;		
    
        t=[[Toner alloc] init];
        [t initWithFrequencies:1209 andThen:770 forLength:150]; //4
        [toners addObject:t];
        [t release], t=nil;
        
        t=[[Toner alloc] init];
        [t initWithFrequencies:1336 andThen:770 forLength:150]; //5
        [toners addObject:t];
        [t release], t=nil;	
    	
        t=[[Toner alloc] init];
        [t initWithFrequencies:1477 andThen:770 forLength:150]; //6
        [toners addObject:t];
        [t release], t=nil;	
    	
        t=[[Toner alloc] init];
        [t initWithFrequencies:1633 andThen:770 forLength:150]; //B
        [toners addObject:t];
        [t release], t=nil;	
    	
        t=[[Toner alloc] init];
        [t initWithFrequencies:1209 andThen:852 forLength:150]; //7
        [toners addObject:t];
        [t release], t=nil;
    	
        t=[[Toner alloc] init];
        [t initWithFrequencies:1336 andThen:852 forLength:150]; //8
        [toners addObject:t];
        [t release], t=nil;	
    	
        t=[[Toner alloc] init];
        [t initWithFrequencies:1477 andThen:852 forLength:150]; //9
        [toners addObject:t];
        [t release], t=nil;	
    	
        t=[[Toner alloc] init];
        [t initWithFrequencies:1633 andThen:852 forLength:150]; //C
        [toners addObject:t];
        [t release], t=nil;		
    	
        t=[[Toner alloc] init];
        [t initWithFrequencies:1209 andThen:941 forLength:150]; //*
        [toners addObject:t];
        [t release], t=nil;
    	
        t=[[Toner alloc] init];
        [t initWithFrequencies:1336 andThen:941 forLength:150]; //0
        [toners addObject:t];
        [t release], t=nil;	
    	
        t=[[Toner alloc] init];
        [t initWithFrequencies:1477 andThen:941 forLength:150]; //#
        [toners addObject:t];
        [t release], t=nil;	
    	
        t=[[Toner alloc] init];
        [t initWithFrequencies:1633 andThen:941 forLength:150]; //D
        [toners addObject:t];
        [t release], t=nil;		
    }
    
    -(IBAction)playTone:(id)sender{
        NSString *s=[[(UIButton *)sender titleLabel] text];
        NSInteger index=-1;
    
        if ([s isEqualToString:@"1"])
            index=0;
        else if ([s isEqualToString:@"2"])
            index=1;
        else if ([s isEqualToString:@"3"])
            index=2;
        else if ([s isEqualToString:@"A"])
            index=3;	
        else if ([s isEqualToString:@"4"])
            index=4;
        else if ([s isEqualToString:@"5"])
            index=5;
        else if ([s isEqualToString:@"6"])
            index=6;
        else if ([s isEqualToString:@"B"])
            index=7;
        else if ([s isEqualToString:@"7"])
            index=8;
        else if ([s isEqualToString:@"8"])
            index=9;
        else if ([s isEqualToString:@"9"])
    	index=10;
        else if ([s isEqualToString:@"C"])
            index=11;	
        else if ([s isEqualToString:@"*"])
            index=12;
        else if ([s isEqualToString:@"0"])
            index=13;
        else if ([s isEqualToString:@"#"])
            index=14;
        else if ([s isEqualToString:@"D"])
            index=15;		
        	
    	
        [(Toner *)[toners objectAtIndex:index] start];
    	
    }
    
  • nobre84nobre84 Posts: 981Registered Users @ @ @
    edited September 2009
    Try to postpone the initAudio call up to the start method ... Looks like it actually prepareds the audio buffers...
  • DutchDutch Posts: 884Registered Users
    edited September 2009
    nobre84 wrote: »
    Try to postpone the initAudio call up to the start method ... Looks like it actually prepareds the audio buffers...

    Perfectly Brilliant. However, the tones all sound the same. I made sure I removed all the hard-coded frequencies..something odd is going on - you need to check it out for yourself as I can't imagine how to explain fully what is going on. Maybe I can only call initAudio once?

    URL sent via PM.
«1
Sign In or Register to comment.