Stereo speech into a file - objective-c

In the recorder application,I'm trying to capture the stereo speech data into a file.
for ( int i=0; i<bufferList->mNumberBuffers; i++ ) {
memcpy(bufferList->mBuffers[i].mData, audio->mBuffers[i].mData, byteCount);
}
The above code contains the recorded speech data. The file writing goes as below.
NSString *root = [NSHomeDirectory() stringByAppendingPathComponent:#"Documents"];
NSString *filePath = [root stringByAppendingPathComponent:#"mic_in.raw"];
if(![[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
[[NSData data] writeToFile:filePath atomically:YES];
}
NSData *myData = [NSData dataWithBytes:audio->mBuffers[0].mData length:byteCount];
NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:filePath];
[handle truncateFileAtOffset:[handle seekToEndOfFile]];
[handle writeData:myData];
myData = [NSData dataWithBytes:audio->mBuffers[1].mData length:byteCount];
[handle truncateFileAtOffset:[handle seekToEndOfFile]];
[handle writeData:myData];
[handle closeFile];
The 'stereo' speech is recorded in 'non interleaved' format.
The saved file contents are not proper. (For e.g. for 15 seconds of speech data, only 2.5 is saved. Saved data also not proper)
The file writing for 'Mono' speech is working fine.
I'm not sure, what is wrong in the 'stereo' speech file writing?

the issue of stereo file writing got it resolved, as follows.
The very frequent file operations at callback was causing the data loss.
So, in callback, the data (after interleaving conversion) is saved in a big buffer and at the end of speech recording, the complete buffer content is written into a file at one shot.
The above approach, resolved the stereo file capturing issue.

Related

Nsdata is not writing to file properly

I have NSData object,it contains 16300 bytes and I am writing to file. Write is success full. But once I want to read from path again, it gives me only 44 bytes.
//writing to path
[audioData writeToFile:recorderFilePath options:NSDataWritingAtomic error:&err];
if (err) {
NSLog(#"Error of writing to file %#",[err localizedDescription]);
}
// reading from path
NSData *paddata = [NSData dataWithContentsOfFile:filePath];
Any help will be appreciated.
Thank you.
Just below code used for write your audio file and read from path.
Write audio file to path
[fileData writeToFile:audioFilePath atomically:YES];
reading from path
NSURL *soundFileURL = [NSURL fileURLWithPath:audioFilePath];

Restoring NSArray from file

I have an array that I serialize, encrypt and then write into a file. The data itself appears to be good but I'm having problems restoring the array back from the file. Here is what I do
NSString *filename = [[self getTransactionLogPath] stringByAppendingPathComponent:transactionLogName];
NSData *data = [[NSData alloc] initWithContentsOfFile:filename];
NSLog(#"encrypted data: %#", data);
EncryptedData *decoder = [[EncryptedData alloc] init];
NSData *decrypted = [decoder reverseTransformedValue:data];
NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithData:decrypted];
I get the filename and read the data from file. EncryptedData decoder runs AES128 on the data and finally I unarchive the array.
The problem is that unarchiveObjectWithData throws an exception
[NSKeyedUnarchiver initForReadingWithData:]:
incomprehensible archive
The tricky thing is that the code works fine in simulator if I keep the NSLog line i.e. I print out the data after reading the file.
On device the NSLog() does not help. Is this a threading problem where the unarchiver starts before the data is read?
I tried adding a delay instead of the NSLog() line but that didn't help.
Any other ways to do the job if I want to encrypt the array before writing to file?

How to run multiple task at the same time safely?

I'm developing a iPhone app and I'm relatively new to objective-c so I hope some one can give a clue.
What im doing is reading a file in chunks and encoding the chuncks into base64 and everything is working fine, the problem is that in this line NSString *str = [data base64EncodedString]; it takes a little bit of time because im encodeing chunks of 256KB, there is no problem with one file the problem is that i'm encoding image files so imagine that I encode 10 images it will be alot of chunks per image so the process can be slow.
this is the process:
*Get the file.
*Read chunck of 256KB of the file.
*Encode chunck to base64.
*Save the encoded chunck and repeat until there is no more bytes to read from the file.
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library assetForURL:referenceURL resultBlock:^(ALAsset *asset)
{
NSUInteger chunkSize =262144;
uint8_t *buffer = calloc(chunkSize, sizeof(*buffer));
ALAssetRepresentation *rep = [asset defaultRepresentation];
NSUInteger length = [rep size];
self.requestsToServer=[[NSMutableArray alloc]init];
NSUInteger offset = 0;
do {
NSUInteger bytesCopied = [rep getBytes:buffer fromOffset:offset length:chunkSize error:nil];
offset += bytesCopied;
NSData *data = [[NSData alloc] initWithBytes:buffer length:bytesCopied];
NSString *str = [data base64EncodedString];
//After this I add the str in a NSMutableURLRequest and I store the request
//in a NSMutableArray for later use.
} while (offset < length);
free(buffer);
buffer = NULL;
}
failureBlock:^(NSError *error)
{
}];
I want to start another thread so I can be encoding the chuncks in paralel and know when the process finish, this way while encoding one chunck I can be encodign another 3 or 4 chunks at the same time.
How I can implement this in a safely way or is this a good idea?
Thanks for your time.
Look at NSOperation and NSOperationQueue.
http://developer.apple.com/library/ios/DOCUMENTATION/Cocoa/Reference/NSOperationQueue_class/Reference/Reference.html
Simply create one NSOperation per chunk and pass them the chunk they need to encode and queue them up.
You can tell the queue how many operations can run simultaneously.
There are lots of good options for doing chunks of work in parallel for iOS.
Take a look at the Apple's Concurrency Programming Guide to get you going.

appending erased file has too much disturbed noice

I am erasing audio file using following code:
NSMutableData *wave =[NSMutableData dataWithContentsOfURL:self.recordedFileURL options:NSDataReadingUncached error:nil];
NSUInteger length = [wave length];
Byte *byteData = (Byte*)malloc(length);
memcpy(byteData, [wave bytes], length);
NSMutableData *data = [NSMutableData dataWithBytes:byteData length:length];
[data replaceBytesInRange:NSMakeRange(length*rangeToCut, length-(length*rangeToCut)) withBytes:NULL length:0];
[data writeToFile:[self.recordedFileURL path] atomically:YES];
it is erasing correctly but after that when i resume my audio ad append resumed part to old part like following:
NSMutableData *part2=[NSMutableData dataWithContentsOfURL:self.soundFileURL options:NSDataReadingUncached error:nil];
NSFileHandle *file = [NSFileHandle fileHandleForWritingToURL:oldURL error:nil];
if (file) {
[file seekToEndOfFile];
[file writeData:part2];
}
then audio files are appended successfully but resumed part of audio has too much disturbance not able to listen that part.
Please help me what is going wrong here.
Is your sample size 16 bits or more? If you cut the audio in the middle of a sample the rest of the stream will be just noise. You need to be sure of length*rangeToCut being a multiple of the sample size.

Write to file not working

I'm trying to combine images in my app into one file and write it to disk.
NSMutableArray *array = [NSMutableArray arrayWithObjects:
[NSData dataWithContentsOfFile:#"0.png"],
[NSData dataWithContentsOfFile:#"1.png"],
[NSData dataWithContentsOfFile:#"2.png"],
nil];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
NSError *error = nil;
NSString *path=#"/Users/myusername/Desktop/_stuff.dat";
[data writeToFile:path options:NSDataWritingAtomic error:&error];
or
NSArray *array = [NSArray arrayWithObjects:
[NSImage imageNamed:#"0"],
[NSImage imageNamed:#"1"],
[NSImage imageNamed:#"2"],
nil];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
NSError *error = nil;
NSString *path=#"/Users/myusername/Desktop/_stuff.dat";
[data writeToFile:path options:NSDataWritingAtomic error:&error];
But both produce a file that is 4KB (empty). If I NSLog the error it is (null). Am I making the data the wrong way?
Edit: If I open the resulting file with a text editor, it looks like this:
I wrote a quick example:
Missing: memory management / error handling / proper file handling
// Archive
NSMutableArray *array = [[NSMutableArray alloc] init];
NSString * input = #"/Users/Anne/Desktop/1.png";
[array addObject:[NSData dataWithContentsOfFile:input]];
[array addObject:[NSData dataWithContentsOfFile:input]];
[array addObject:[NSData dataWithContentsOfFile:input]];
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
NSString *path = #"/Users/Anne/Desktop/archive.dat";
[data writeToFile:path options:NSDataWritingAtomic error:nil];
// Unarchive
NSMutableArray *archive = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
NSData * firstObject = [archive objectAtIndex:0];
NSString * output = #"/Users/Anne/Desktop/2.png";
NSURL *fileURL = [[NSURL alloc] initFileURLWithPath:output];
[firstObject writeToURL:fileURL atomically:YES];
You can also add NSImages to the NSMutableArray:
NSString * input = #"/Users/Anne/Desktop/1.png";
NSImage *image = [[NSImage alloc] initWithContentsOfFile: input];
[array addObject:image];
But that will significantly increase the file size.
Response to the following comment:
So if I only need to access an image at runtime (in the archive), is there a way to access that image at an index without unarchiving the whole thing? Seems like unnecessary overhead to me.
I assume you're still struggling with this problem?
Hiding (or encrypting) app resources?
Like i mentioned earlier, combining all files into one big file does the trick.
Just make sure you remember the file-length of each file and file-order.
Then you can extract any specific file you like without reading the whole file.
This might be a more sufficient way if you only need to extract one file at the time.
Quick 'dirty' sample:
// Two sample files
NSData *fileOne = [NSData dataWithContentsOfFile:#"/Users/Anne/Desktop/1.png"];
NSData *fileTwo = [NSData dataWithContentsOfFile:#"/Users/Anne/Desktop/2.png"];
// Get file length
int fileOneLength = [fileOne length];
int fileTwoLength = [fileTwo length];
// Combine files into one container
NSMutableData * container = [[NSMutableData alloc] init];
[container appendData:fileOne];
[container appendData:fileTwo];
// Write container to disk
[container writeToFile:#"/Users/Anne/Desktop/container.data" atomically:YES];
// Read data and extract sample files again
NSData *containerFile = [NSData dataWithContentsOfFile:#"/Users/Anne/Desktop/container.data"];
NSData *containerFileOne =[containerFile subdataWithRange:NSMakeRange(0, fileOneLength)];
NSData *containerFileTwo =[containerFile subdataWithRange:NSMakeRange(fileOneLength, fileTwoLength)];
// Write extracted files to disk (will be exactly the same)
[containerFileOne writeToFile:#"/Users/Anne/Desktop/1_extracted.png" atomically:YES];
[containerFileTwo writeToFile:#"/Users/Anne/Desktop/2_extracted.png" atomically:YES];
// Only extract one file from the container
NSString * containerPath = #"/Users/Anne/Desktop/container.data";
NSData * oneFileOnly = [[NSFileHandle fileHandleForReadingAtPath:containerPath] readDataOfLength:fileOneLength];
// Write result to disk
[oneFileOnly writeToFile:#"/Users/Anne/Desktop/1_one_file.png" atomically:YES];
Tip:
You can also save the 'index' inside the container file.
For example: The first 500 bytes contain the required information.
When you need a specific file: Read the index, get the file position and extract it.
You are archiving a NSMutable array of NSImage. This two classes conform to the NSCoding protocol required by NSKeyedArchiver, so I don't see where would be your problem.
So, here are many ideas to test.
First, are you sure that the data you think you have are valid? In your first code snippet, you write [NSData dataWithContentsOfFile:#"0.png"]. This method expects an absolute file path.
Assuming the problem is not in your code, just in your question, let's continue:
Do you have something different than nil in the variable data after your archiving? Ie, after the assignement to data, can you add this code. If the assertion fail, you will get an exception at runtime:
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:array];
NSAssert(nil != data, #"My object data is nil after archiving");
If the problem was not here, what is the return of the line [data writeToFile:path options:NSDataWritingAtomic error:&error];
(Not the variable error, but the return value of the call to the method - writeToFile: options: error:)
What happens if you simplify your code and just do this:
result = [NSKeyedArchiver archiveRootObject:data
toFile:archivePath];
If everything was ok, have you tried to unarchive your file with NSKeyedUnarchiver?
The problem is that [NSData dataWithContentsOfFile:#"0.png"] looks for the file "0.png" in the current directory, but what the application thinks of as the current directory is probably not the place you're expecting. For graphical apps, you should always either use an absolute path or a path relative to some place that you can get the absolute path of (e.g. your app bundle, the application support directory, some user-selected location).
For command-line tools, using the current directory is more common. But I doubt that's the case here.
Another thing I noticed on Mavericks and up is that the folders in the path must be in existence. Meaning you must create the folder structure prior to saving into that folder. If you try to write to a folder on the desktop or elsewhere, even with sandboxing off, it will fail if the folder does not exist. I know this has been answered already, but I found that my issue continued regardless, but once I make sure that the folder structure was in place, I could do my writing to that folder.
On a side note: I'm sure that you could do this from NSFileManager, and I'll be doing that myself once I finalize my app structure, but hope this helps someone else lost in the sauce.