views:

70

answers:

1

I want to generate a custom DTMF tone and play it on the iPhone. In order to do so, I have created and allocated a memory buffer with a custom tone (ptr). Now I want to create a NSData object, initialized with the memory buffer, and pass it to AVAudioPlayer using initWithData:error: instance method.

I wrote the following code, but when I press the button "Play", it crashes.

#import "AudioPlayerViewController.h"
#include <stdlib.h>
#include <math.h>
#define SIZE 10
#define LENGTH 65535
const int PLAYBACKFREQ = 44100;
const float PI2 = 3.14159265359f * 2;
const int freq1 = 697;
const int freq2 = 1209;



@implementation AudioPlayerViewController

@synthesize playButton, stopButton;

- (void)viewDidLoad {
    [super viewDidLoad];
 // Allocate space for an array with ten elements of type int.
int *ptr = malloc(SIZE * sizeof(int));
if (ptr == NULL) NSLog(@"Error: Memory buffer could not be allocated.");
else NSLog(@"Allocation succeeded.");

 // The formula for the tone, the content of the buffer.
for(int i=0; i<SIZE; i++) ptr[i] = (sin(i*(PI2*(PLAYBACKFREQ/freq1))) + sin(i*    (PI2*(PLAYBACKFREQ/freq2)))) * 16383;
NSData *myData = [[NSData alloc] initWithBytesNoCopy:ptr length:SIZE];
free(ptr);
ptr = NULL;
audioPlayer = [[AVAudioPlayer alloc] initWithData:myData error:&error];
audioPlayer.numberOfLoops = -1;
}
-(IBAction) playAudio: (id) sender {
    if (audioPlayer == nil) NSLog([error description]);             
    else [audioPlayer play];
}
-(IBAction) stopAudio: (id) sender { [audioPlayer stop]; }

- (void)dealloc {
    [audioPlayer release];
    [myData release];
    [super dealloc];
}

@end

In the documentation, the description of method initWithBytesNoCopy reads:

A buffer containing data for the new object. bytes must point to a memory block allocated with malloc.

So I have already done this, but it doesn't work.

Any kind of help will be appreciated!

+1  A: 

You create an NSData without copying the data and then you free the data, so NSData now has a dangling pointer. Remove the free(ptr); line and try it again. NSData will free the data by itself when it is done with it.

Hollance
I tried doing that but it doesn't help.
The second thing that is suspect is that you're giving AVAudioPlayer raw data and it probably doesn't know how to interpret that. Audio files typically have a header that describes the sample rate, the format of the samples, etc. You can fix this by adding a fake header, for example a WAV header which is quite simple. You may need to convert your int's to 16-bit values, though.
Hollance
Here is a demo project that shows how to do this: http://github.com/hollance/AVBufferPlayer
Hollance