How to add playable (e.g. wav, wmv) header with PCM data / buffer in iOS?

I am trying to add a wav header on top of raw PCM data to make it playable through AVAudioPlayer. But I could not find any solution or source code for iOS using Objective-C / Swift. Although I found this one , but it does not have the correct answer.

But I found a piece of code here that is in C, and also contains some problem. The wav file does not play correctly, which is generated from this code.

I gave the codes below which I have encoded so far.

int NumChannels = AUDIO_CHANNELS_PER_FRAME; short BitsPerSample = AUDIO_BITS_PER_CHANNEL; int SamplingRate = AUDIO_SAMPLE_RATE; int numOfSamples = [[NSData dataWithContentsOfFile:filePath] length]; int ByteRate = NumChannels*BitsPerSample*SamplingRate/8; short BlockAlign = NumChannels*BitsPerSample/8; int DataSize = NumChannels*numOfSamples*BitsPerSample/8; int chunkSize = 16; int totalSize = 36 + DataSize; short audioFormat = 1; if((fout = fopen([wavFilePath cStringUsingEncoding:1], "w")) == NULL) { printf("Error opening out file "); } fwrite("RIFF", sizeof(char), 4,fout); fwrite(&totalSize, sizeof(int), 1, fout); fwrite("WAVE", sizeof(char), 4, fout); fwrite("fmt ", sizeof(char), 3, fout); fwrite(&chunkSize, sizeof(int),1,fout); fwrite(&audioFormat, sizeof(short), 1, fout); fwrite(&NumChannels, sizeof(short),1,fout); fwrite(&SamplingRate, sizeof(int), 1, fout); fwrite(&ByteRate, sizeof(int), 1, fout); fwrite(&BlockAlign, sizeof(short), 1, fout); fwrite(&BitsPerSample, sizeof(short), 1, fout); fwrite("data", sizeof(char), 3, fout); fwrite(&DataSize, sizeof(int), 1, fout); 

The file plays too fast, the sound is distorted and only the first 10-20 seconds are played. I think the wav header is not generated correctly (because I can play the same PCM data / buffer using AudioUnit / AudioQueue). So what am I missing in my code? Any help would be greatly appreciated.

Thanks in advance.

+2
source share
1 answer

Well, I answer my question if it helps someone else. After several days of tireless attempts, finally, I succeeded. The following is a complete function written using Objective-C and C. It takes the path to the file as a parameter that contains the PCM RAW data directly captured from the microphone and returns the path to the file that contains the PCM data and then the corresponding header information wav. You can then play this file using AVAudioPlayer or AVPlayer. Here is the code ...

 - (NSURL *) getAndCreatePlayableFileFromPcmData:(NSString *)filePath { NSString *wavFileName = [[filePath lastPathComponent] stringByDeletingPathExtension]; NSString *wavFileFullName = [NSString stringWithFormat:@"%@.wav",wavFileName]; [self createFileWithName:wavFileFullName]; NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); NSString *docsDir = [dirPaths objectAtIndex:0]; NSString *wavFilePath = [docsDir stringByAppendingPathComponent:wavFileFullName]; NSLog(@"PCM file path : %@",filePath); FILE *fout; short NumChannels = AUDIO_CHANNELS_PER_FRAME; short BitsPerSample = AUDIO_BITS_PER_CHANNEL; int SamplingRate = AUDIO_SAMPLE_RATE; int numOfSamples = [[NSData dataWithContentsOfFile:filePath] length]; int ByteRate = NumChannels*BitsPerSample*SamplingRate/8; short BlockAlign = NumChannels*BitsPerSample/8; int DataSize = NumChannels*numOfSamples*BitsPerSample/8; int chunkSize = 16; int totalSize = 46 + DataSize; short audioFormat = 1; if((fout = fopen([wavFilePath cStringUsingEncoding:1], "w")) == NULL) { printf("Error opening out file "); } fwrite("RIFF", sizeof(char), 4,fout); fwrite(&totalSize, sizeof(int), 1, fout); fwrite("WAVE", sizeof(char), 4, fout); fwrite("fmt ", sizeof(char), 4, fout); fwrite(&chunkSize, sizeof(int),1,fout); fwrite(&audioFormat, sizeof(short), 1, fout); fwrite(&NumChannels, sizeof(short),1,fout); fwrite(&SamplingRate, sizeof(int), 1, fout); fwrite(&ByteRate, sizeof(int), 1, fout); fwrite(&BlockAlign, sizeof(short), 1, fout); fwrite(&BitsPerSample, sizeof(short), 1, fout); fwrite("data", sizeof(char), 4, fout); fwrite(&DataSize, sizeof(int), 1, fout); fclose(fout); NSMutableData *pamdata = [NSMutableData dataWithContentsOfFile:filePath]; NSFileHandle *handle; handle = [NSFileHandle fileHandleForUpdatingAtPath:wavFilePath]; [handle seekToEndOfFile]; [handle writeData:pamdata]; [handle closeFile]; return [NSURL URLWithString:wavFilePath]; } 

But this function only works with the following sound settings.

 // Audio settings. #define AUDIO_SAMPLE_RATE 8000 #define AUDIO_FRAMES_PER_PACKET 1 #define AUDIO_CHANNELS_PER_FRAME 1 #define AUDIO_BITS_PER_CHANNEL 16 #define AUDIO_BYTES_PER_PACKET 2 #define AUDIO_BYTES_PER_FRAME 2 
+6
source

All Articles