I'd like to reverse an existing audio file (e.g. WAV, CAF, ...) on iOS. Any suggestions on how to achieve this? Open-source libraries?
问题:
回答1:
I have worked on a sample app, which records what user says and plays them backwards. I have used CoreAudio to achieve this. Link to app code.
As each sample is 16-bits in size(2 bytes)(mono channel). You can load each sample at a time by copying it into a different buffer by starting at the end of the recording and reading backwards. When you get to the start of the data you have reversed the data and playing will be reversed.
// set up output file
AudioFileID outputAudioFile;
AudioStreamBasicDescription myPCMFormat;
myPCMFormat.mSampleRate = 16000.00;
myPCMFormat.mFormatID = kAudioFormatLinearPCM ;
myPCMFormat.mFormatFlags = kAudioFormatFlagsCanonical;
myPCMFormat.mChannelsPerFrame = 1;
myPCMFormat.mFramesPerPacket = 1;
myPCMFormat.mBitsPerChannel = 16;
myPCMFormat.mBytesPerPacket = 2;
myPCMFormat.mBytesPerFrame = 2;
AudioFileCreateWithURL((__bridge CFURLRef)self.flippedAudioUrl,
kAudioFileCAFType,
&myPCMFormat,
kAudioFileFlags_EraseFile,
&outputAudioFile);
// set up input file
AudioFileID inputAudioFile;
OSStatus theErr = noErr;
UInt64 fileDataSize = 0;
AudioStreamBasicDescription theFileFormat;
UInt32 thePropertySize = sizeof(theFileFormat);
theErr = AudioFileOpenURL((__bridge CFURLRef)self.recordedAudioUrl, kAudioFileReadPermission, 0, &inputAudioFile);
thePropertySize = sizeof(fileDataSize);
theErr = AudioFileGetProperty(inputAudioFile, kAudioFilePropertyAudioDataByteCount, &thePropertySize, &fileDataSize);
UInt32 dataSize = fileDataSize;
void* theData = malloc(dataSize);
//Read data into buffer
UInt32 readPoint = dataSize;
UInt32 writePoint = 0;
while( readPoint > 0 )
{
UInt32 bytesToRead = 2;
AudioFileReadBytes( inputAudioFile, false, readPoint, &bytesToRead, theData );
AudioFileWriteBytes( outputAudioFile, false, writePoint, &bytesToRead, theData );
writePoint += 2;
readPoint -= 2;
}
free(theData);
AudioFileClose(inputAudioFile);
AudioFileClose(outputAudioFile);
回答2:
A WAV file just contains raw PCM samples. If you play them in the reverse order, you will get the reverse sound. See this question for details. (and also this search)
回答3:
Kiran's answer in Swift 2.2:
let forwardAudioURL: NSURL = ... // wherever your original audio is
let reversedAudioURL: NSURL = ... // wherever you want the reversed file to go
// Load forward audio into originalAudioFile
var originalAudioFile: AudioFileID = nil
let possibleError1 = AudioFileOpenURL(forwardAudioURL,
AudioFilePermissions.ReadPermission,
0,
&originalAudioFile)
// Load the size in bytes of the original audio into originalAudioSize variable
var originalAudioSize: Int64 = 0
var propertySize: UInt32 = 8
let possibleError2 = AudioFileGetProperty(originalAudioFile,
kAudioFilePropertyAudioDataByteCount,
&propertySize,
&originalAudioSize)
if possibleError1 != 0 || possibleError2 != 0 {
// Handle errors if you want
}
// Set up file that the reversed audio will be loaded into
var reversedAudioFile: AudioFileID = nil
var format = AudioStreamBasicDescription()
format.mSampleRate = 16000
format.mFormatID = kAudioFormatLinearPCM
format.mChannelsPerFrame = 1
format.mFramesPerPacket = 1
format.mBitsPerChannel = 16
format.mBytesPerPacket = 2
format.mBytesPerFrame = 2
AudioFileCreateWithURL(reversedAudioURL,
kAudioFileCAFType,
&format,
AudioFileFlags.EraseFile,
&reversedAudioFile)
// Read data into the reversedAudioFile
var readPoint: Int64 = originalAudioSize
var writePoint: Int64 = 0
var buffer: Int16 = 0
while readPoint > 0 {
var bytesToRead: UInt32 = 2;
AudioFileReadBytes(originalAudioFile,
false,
readPoint,
&bytesToRead,
&buffer)
AudioFileWriteBytes(reversedAudioFile,
false,
writePoint,
&bytesToRead,
&buffer)
writePoint += 2
readPoint -= 2
}
AudioFileClose(originalAudioFile)
AudioFileClose(reversedAudioFile)
回答4:
Using libsndfile, I was able to read in the recorded audio sample. The following code snippet then shows how to open the input file, and write the output in reversed order. You should note though that all data is read in memory!
SF_INFO info_read;
info_read.format = 0;
SNDFILE* sndfilein = sf_open("my_input_file.caf", SFM_READ, &info_read);
SF_INFO info_write;
info_write.format = info.format;
info_write.channels = info.channels;
info_write.frames = info.frames;
info_write.samplerate = info.samplerate;
info_write.sections = info.sections;
info_write.seekable = info.seekable;
SNDFILE* sndfileout = sf_open("my_output_file.caf", SFM_RDWR, &info_write);
int* buf = new int[8000 * 30];
int framesRead = sf_readf_int(sndfilein, buf, info.frames);
for (int i = 0; i < info.frames; i++)
sf_writef_int(sndfileout, &buf[info.frames - i], 1);
delete[] buf;
sf_close(sndfilein);
sf_close(sndfileout);