Record audio and save permanently in iOS - ios

I have made 2 iPhone apps which can record audio and save it to a file and play it back again.
One of them uses AVAudiorecorder and AVAudioplayer.
The second one is Apple's SpeakHere example with Audio Queues.
Both run on Simulater as well as the Device.
BUT when I restart either app the recorded file is not found!!!
I've tried all possible suggestions found on stackoverflow but it still doesnt work!
This is what I use to save the file:
NSArray *dirPaths;
NSString *docsDir;
dirPaths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory, NSUserDomainMask, YES);
docsDir = [dirPaths objectAtIndex:0];
NSString *soundFilePath = [docsDir stringByAppendingPathComponent:#"sound1.caf"];
NSURL *soundFileURL = [NSURL fileURLWithPath:soundFilePath];

Ok I finally solved it. The problem was that I was setting up the AVAudioRecorder and file the path in the viewLoad of my ViewController.m overwriting existing files with the same name.
After recording and saving the audio to file and stopping the app, I could find the file in Finder. (/Users/xxxxx/Library/Application Support/iPhone Simulator/6.0/Applications/0F107E80-27E3-4F7C-AB07-9465B575EDAB/Documents/sound1.caf)
When I restarted the application the setup code for the recorder (from viewLoad) would just overwrite my old file called:
sound1.caf
with a new one. Same name but no content.
The play back would just play an empty new file. --> No Sound obviously.
So here is what I did:
I used NSUserdefaults to save the path of the recorded file name to be retrieved later in my playBack method.
cleaned viewLoad in ViewController.m :
- (void)viewDidLoad
{
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
[audioSession setActive:YES error:nil];
[recorder setDelegate:self];
[super viewDidLoad];
}
edited record in ViewController.m :
- (IBAction) record
{
NSError *error;
// Recording settings
NSMutableDictionary *settings = [NSMutableDictionary dictionary];
[settings setValue: [NSNumber numberWithInt:kAudioFormatLinearPCM] forKey:AVFormatIDKey];
[settings setValue: [NSNumber numberWithFloat:8000.0] forKey:AVSampleRateKey];
[settings setValue: [NSNumber numberWithInt: 1] forKey:AVNumberOfChannelsKey];
[settings setValue: [NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
[settings setValue: [NSNumber numberWithBool:NO] forKey:AVLinearPCMIsBigEndianKey];
[settings setValue: [NSNumber numberWithBool:NO] forKey:AVLinearPCMIsFloatKey];
[settings setValue: [NSNumber numberWithInt: AVAudioQualityMax] forKey:AVEncoderAudioQualityKey];
NSArray *searchPaths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentPath_ = [searchPaths objectAtIndex: 0];
NSString *pathToSave = [documentPath_ stringByAppendingPathComponent:[self dateString]];
// File URL
NSURL *url = [NSURL fileURLWithPath:pathToSave];//FILEPATH];
//Save recording path to preferences
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setURL:url forKey:#"Test1"];
[prefs synchronize];
// Create recorder
recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];
[recorder prepareToRecord];
[recorder record];
}
edited playback in ViewController.m:
-(IBAction)playBack
{
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
[audioSession setActive:YES error:nil];
//Load recording path from preferences
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
temporaryRecFile = [prefs URLForKey:#"Test1"];
player = [[AVAudioPlayer alloc] initWithContentsOfURL:temporaryRecFile error:nil];
player.delegate = self;
[player setNumberOfLoops:0];
player.volume = 1;
[player prepareToPlay];
[player play];
}
and added a new dateString method to ViewController.m:
- (NSString *) dateString
{
// return a formatted string for a file name
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = #"ddMMMYY_hhmmssa";
return [[formatter stringFromDate:[NSDate date]] stringByAppendingString:#".aif"];
}
Now it can load the last recorded file via NSUserdefaults loading it with:
//Load recording path from preferences
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
temporaryRecFile = [prefs URLForKey:#"Test1"];
player = [[AVAudioPlayer alloc] initWithContentsOfURL:temporaryRecFile error:nil];
in (IBAction)playBack. temporaryRecFile is a NSURL variable in my ViewController class.
declared as following ViewController.h :
#interface SoundRecViewController : UIViewController <AVAudioSessionDelegate,AVAudioRecorderDelegate, AVAudioPlayerDelegate>
{
......
......
NSURL *temporaryRecFile;
AVAudioRecorder *recorder;
AVAudioPlayer *player;
}
......
......
#end

Related

How to set settings to get recorded audio file size in kb?

I'm working on audio recording and uploading. While uploading 10secs audio I'm getting the 4GB data, I browsed and followed one of the answers in StackOverflow, changed settings as shown below and audio file format to .3gp, but data size not reduced.
-(void) startRecording{
[_recordButton setTitle:#"Stop" forState:UIControlStateNormal];
NSError *error;
// Recording settings
NSLog(#"%f", [[AVAudioSession sharedInstance] sampleRate]);
NSMutableDictionary *settings = [NSMutableDictionary dictionary];
[settings setValue: [NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey];
[settings setValue: [NSNumber numberWithFloat:2000.0] forKey:AVSampleRateKey];
[settings setValue: [NSNumber numberWithInt: 1] forKey:AVNumberOfChannelsKey];
[settings setValue: [NSNumber numberWithInt: AVAudioQualityMax] forKey:AVEncoderAudioQualityKey];
[settings setValue:[NSNumber numberWithFloat:12000.0] forKey:AVEncoderBitRateKey];
NSArray *searchPaths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentPath_ = [searchPaths objectAtIndex: 0];
NSString *pathToSave = [documentPath_ stringByAppendingPathComponent:#"AudioName.3gp"];
// File URL
NSURL *url = [NSURL fileURLWithPath:pathToSave];//FILEPATH];
//Save recording path to preferences
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setURL:url forKey:#"Test1"];
[prefs synchronize];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
// Create recorder
recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];
recorder.delegate=self;
[recorder recordForDuration:10];
[self startTimerToMoveSlider];
}
Can anybody please guide me
Finally solved audio file size issue, here is my code for recording 30seconds audio and getting file size nearly 60kb-70kb.
-(void) startRecording{
[_recordButton setTitle:#"Stop" forState:UIControlStateNormal];
NSError *error;
NSString *pathToSave = [NSString stringWithFormat:#"%#/MySound.m4a", DOCUMENTS_FOLDER];
// File URL
NSURL *url = [NSURL fileURLWithPath:pathToSave];//FILEPATH];
// Recording settings
NSDictionary *settings = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithInt: kAudioFormatMPEG4AAC], AVFormatIDKey,
[NSNumber numberWithFloat:8000.0], AVSampleRateKey,
[NSNumber numberWithInt: 1], AVNumberOfChannelsKey,[NSNumber numberWithInt:12000],AVEncoderBitRateKey,
nil];
NSData *audioData = [NSData dataWithContentsOfFile:[url path] options: 0 error:&error];
//Save recording path to preferences
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs setURL:url forKey:#"Test1"];
[prefs synchronize];
// Create recorder
recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];
recorder.delegate=self;
[recorder prepareToRecord];
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
[[AVAudioSession sharedInstance] setActive:YES error:nil];
[recorder recordForDuration:30];//recording for 30secs
[self startTimerToMoveSlider];//to move slider while recording
}
Note : #define DOCUMENTS_FOLDER [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"]

AVRecorder files deleted each time app is rebuilt - iOS

I have an app which makes recordings using AVAudioRecorder. Its works and saves the audio files just fine. But when I rebuild the app, the audio files are deleted.
Is that normal? I would have thought so, but just wanted to make sure. I can't find anything about this online. Does Xcode delete any new files made by the app, each time a new build is made?
UPDATE
The code I am using to record the audio is as follows:
// Setup audio recorder to save file.
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
[audioSession setActive:YES error:nil];
[audio_recorder setDelegate:self];
// Set the recording options such as quality.
NSMutableDictionary *settings = [NSMutableDictionary dictionary];
[settings setValue:[NSNumber numberWithInt:kAudioFormatLinearPCM] forKey:AVFormatIDKey];
[settings setValue:[NSNumber numberWithFloat:8000.0] forKey:AVSampleRateKey];
[settings setValue:[NSNumber numberWithInt:1] forKey:AVNumberOfChannelsKey];
[settings setValue:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
[settings setValue:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsBigEndianKey];
[settings setValue:[NSNumber numberWithBool:NO] forKey:AVLinearPCMIsFloatKey];
[settings setValue:[NSNumber numberWithInt:AVAudioQualityMax] forKey:AVEncoderAudioQualityKey];
NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentPath_ = [searchPaths objectAtIndex:0];
NSString *pathToSave = [documentPath_ stringByAppendingPathComponent:currentDate];
// Construct the audio file save URL.
NSURL *url = [NSURL fileURLWithPath:pathToSave];
// Setup the audio recorder.
NSError *error;
audio_recorder = [[AVAudioRecorder alloc] initWithURL:url settings:settings error:&error];
if (error == nil) {
// Now begin the recording.
[audio_recorder prepareToRecord];
[audio_recorder record];
}
Thanks for your time, Dan.

iPhone - Problems Saving Audio After Recording

I a button that records audio when isNotRecording is false and plays audio when isNotRecording is true. Here is my code in the viewDidLoad function:
NSArray *pathComponents = [NSArray arrayWithObjects:
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject],
#"MyAudioMemo.m4a",
nil];
NSURL *outputFileURL = [NSURL fileURLWithPathComponents:pathComponents];
// Setup audio session
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
// Define the recorder setting
NSMutableDictionary *recordSetting = [[NSMutableDictionary alloc] init];
[recordSetting setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey];
[recordSetting setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey];
[recordSetting setValue:[NSNumber numberWithInt: 2] forKey:AVNumberOfChannelsKey];
// Initiate and prepare the recorder
recorder = [[AVAudioRecorder alloc] initWithURL:outputFileURL settings:recordSetting error:NULL];
recorder.delegate = self;
recorder.meteringEnabled = YES;
[recorder prepareToRecord];
Here is my code to play the sound or record:
if (isNotRecording==NO){
if (player.playing) {
[player stop];
}
if (!recorder.recording) {
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setActive:YES error:nil];
// Start recording
[recorder record];
}
}
else{
if (!recorder.recording){
player = [[AVAudioPlayer alloc] initWithContentsOfURL:recorder.url error:nil];
[player setDelegate:self];
[player play];
}
}
And here is my code to stop the playing/recording:
[recorder stop];
[player stop];
Now, everything works almost perfectly (i.e. I can record and play sounds fine). However, there are two issues. The major one is that after I close out the app and try to play the sound, it does not have a sound to play. I want it to play the previous recording. That is my main issue, but it would also be great if I could reduce the lag from when I press the button and the sound plays. Sometimes, if I press the button and release it very fast, no sound plays at all. Any suggestions are greatly appreciated. However, again, the main issue I need fixed is that the recording doesn't save after I close out the app.
I think what's happening is that when you initialize your AVAudioRecorder when the view loads then that will delete any existing file at the target location, irrespective of whether you start recording at that stage. So I think that's how the file is going missing.
Simplest may be just not to call [recorder prepareToRecord]; when you do, as I suspect that's when your recording is getting deleted.
Or you might want to use a temporary file while recording and move it to the final location when you're notified that the recording is finished, in order to avoid that issue. Code is something like:
NSArray *pathComponents = [NSArray arrayWithObjects:
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject],
#"MyAudioMemoTemp.m4a",
nil];
NSURL *outputFileURL = [NSURL fileURLWithPathComponents:pathComponents];
// Setup audio session
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
// Define the recorder setting
NSMutableDictionary *recordSetting = [[NSMutableDictionary alloc] init];
[recordSetting setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey];
[recordSetting setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey];
[recordSetting setValue:[NSNumber numberWithInt: 2] forKey:AVNumberOfChannelsKey];
// Initiate and prepare the recorder
recorder = [[AVAudioRecorder alloc] initWithURL:outputFileURL settings:recordSetting error:NULL];
recorder.delegate = self;
recorder.meteringEnabled = YES;
[recorder prepareToRecord];
if (isNotRecording==NO){
if (player.playing) {
[player stop];
}
if (!recorder.recording) {
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setActive:YES error:nil];
// Start recording
[recorder record];
}
}
else{
if (!recorder.recording){
NSArray *pathComponents = [NSArray arrayWithObjects:
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject],
#"MyAudioMemo.m4a",
nil];
NSURL *inputFileURL = [NSURL fileURLWithPathComponents:pathComponents];
player = [[AVAudioPlayer alloc] initWithContentsOfURL:inputFileURL error:nil];
[player setDelegate:self];
[player play];
}
}
- (void)audioRecorderDidFinishRecording:(AVAudioRecorder *)recorder
                            successfully:(BOOL)flag
{
if (successfully) {
// Copy temp file used during recording to replace that used when playing
//
pathComponents = [NSArray arrayWithObjects:
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject],
#"MyAudioMemo.m4a",
nil];
NSURL *targetFileURL = [NSURL fileURLWithPathComponents:pathComponents];
NSError *error = nil;
[[NSFileManager defaultManager] removeItemAtURL:targetFileURL error:&error];
error = nil;
[[NSFileManager defaultManager] copyItemAtURL:recorder.url toURL:targetFileURL error:&error];
}
}

Audio processing in iOS to get volume and pitch

I'm attempting to create a realtime audio analyzer on iOS7. What I'm looking to get is volume and pitch from the native microphone on an iPod Touch Gen 5, and write to a CSV along with a timestamp. I'd like to break it up into 7 channels, and sample at 8Hz. I've looked at a bunch of documentation and code samples, but can't get anything to work.
I'm trying to start something simple now from scratch, but it seems to me that there is nothing outlining how I can achieve what I mentioned above.
Most recently I've tried AVAudioSessionCategoryAudioProcessing hoping to be able to use it for signal processing, but the Audio Session docs suggest that only automated signal processing can be done...and only in voice or video chat modes.
- (void)analyzeAudio
{
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
audioUnit = (AudioUnit*)malloc(sizeof(AudioUnit));
NSError *activationError = nil;
BOOL success = [[AVAudioSession sharedInstance] setActive: YES error: &activationError];
if (!success)
{
NSLog(#"AudioSession could not init");
}
[audioSession setCategory:AVAudioSessionCategoryAudioProcessing error:nil];
[audioSession setActive:YES error:nil];
}
Is there a simple way with Audio Session to get what I'm looking for?
Found out that I can use the AVAudioRecorder method updateMeters on a timer to get the peakPowerForChannel: value at some interval.
- (void)recordAudio
{
_audioSession = [AVAudioSession sharedInstance];
NSError *error;
[_audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];
[_audioSession setActive:YES error:&error];
NSMutableDictionary *settings = [NSMutableDictionary dictionary];
[settings setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey];
[settings setValue:[NSNumber numberWithFloat:8000.0] forKey:AVSampleRateKey];
[settings setValue:[NSNumber numberWithInt:1] forKey:AVNumberOfChannelsKey];
[settings setValue:[NSNumber numberWithFloat:16000] forKey:AVEncoderBitRateKey];
[settings setValue:[NSNumber numberWithInt:AVAudioQualityMin] forKey:AVEncoderAudioQualityForVBRKey];
NSArray *dirPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsPath = [dirPath objectAtIndex:0];
long currentTime = [[NSDate date] timeIntervalSince1970];
NSString *filePath = [documentsPath stringByAppendingPathComponent:[NSString stringWithFormat:#"audio_%ld.aac", currentTime]];
NSURL *audioFileURL = [NSURL fileURLWithPath:filePath];
_audioRecorder = [[AVAudioRecorder alloc] initWithURL:audioFileURL settings:settings error:&error];
if (error)
{
NSLog(#"audio record error: %#", [error localizedDescription]);
} else {
[_audioRecorder prepareToRecord];
_audioRecorder.meteringEnabled = YES;
[_audioRecorder record];
[self addTextToLog:#"Recording Audio"];
self.audioTimer = [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:#selector(updateAudioMeters) userInfo:nil repeats:YES];
}
}
- (void)updateAudioMeters
{
[_audioRecorder updateMeters];
NSLog(#"pkPwr: %f", [_audioRecorder peakPowerForChannel:0]);
}

How to name recorded file from AVAudioRecorder

I am making an iOS app where I need to record speech using AVAudioRecorder and then I want to rename the file. Right now, I can successfully record the speech but I don't know how to give the file a custom name. How can I give the recorded file a custom name? Any help is appreciated.
In the viewDidLoad:
NSArray *pathComponents = [NSArray arrayWithObjects:
[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject],
#"MyAudioMemo.m4a",
nil];
outputFileURL = [NSURL fileURLWithPathComponents:pathComponents];
// Setup audio session
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
// Define the recorder setting
NSMutableDictionary *recordSetting = [[NSMutableDictionary alloc] init];
[recordSetting setValue:[NSNumber numberWithInt:kAudioFormatMPEG4AAC] forKey:AVFormatIDKey];
[recordSetting setValue:[NSNumber numberWithFloat:44100.0] forKey:AVSampleRateKey];
[recordSetting setValue:[NSNumber numberWithInt: 2] forKey:AVNumberOfChannelsKey];
// Initiate and prepare the recorder
recorder = [[AVAudioRecorder alloc] initWithURL:outputFileURL settings:recordSetting error:nil];
recorder.delegate = self;
recorder.meteringEnabled = YES;
[recorder prepareToRecord];
and all the other methods:
- (IBAction)recordPressed:(id)sender {
if (!recorder.recording) {
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setActive:YES error:nil];
// Start recording
[recorder record];
NSLog(#"Recording...");
} else {
// Pause recording
[recorder pause];
NSLog(#"Paused...");
}
}
- (IBAction)stopPressed:(id)sender {
[recorder stop];
NSLog(#"Stopped...");
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
[audioSession setActive:NO error:nil];
}
You can simple move your file to another path, when you do that, you can specify a new name for the file, is the exactly same behavior of the mv command in shell.
There is a very simple snippet to you understand how to rename your file using move the FileManager moveItemAtPath:toPath:error method:
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *docsDir = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
NSString *newPath = [docsDir stringByAppendingPathComponent:#"newname.m4a"];
// Try to move your file and the current path to newPath
if ([fileManager moveItemAtPath:currentPath toPath:newPath error:&error] != YES)
{
NSLog(#"Error: %#", [error localizedDescription]);
}
else
{
// File moved success
}

Resources