Converting .m4a file to .aiff using AudioConverter Swift
Skip the AudioConverterGetProperty
You actually are not using it.
The following snippet will convert an audio file to AIFF: it reads the sourceFile
in one of the supported formats, creates an AIFF
encoder, and loops through it using a bufferByteSize
buffer. Errors are mildly handled.
Complete code, swift 3:
func convertAudio(_ url: URL, outputURL: URL) {
var error : OSStatus = noErr
var destinationFile : ExtAudioFileRef? = nil
var sourceFile : ExtAudioFileRef? = nil
var srcFormat : AudioStreamBasicDescription = AudioStreamBasicDescription()
var dstFormat : AudioStreamBasicDescription = AudioStreamBasicDescription()
ExtAudioFileOpenURL(url as CFURL, &sourceFile)
var thePropertySize: UInt32 = UInt32(MemoryLayout.stride(ofValue: srcFormat))
ExtAudioFileGetProperty(sourceFile!,
kExtAudioFileProperty_FileDataFormat,
&thePropertySize, &srcFormat)
dstFormat.mSampleRate = 44100 //Set sample rate
dstFormat.mFormatID = kAudioFormatLinearPCM
dstFormat.mChannelsPerFrame = 1
dstFormat.mBitsPerChannel = 16
dstFormat.mBytesPerPacket = 2 * dstFormat.mChannelsPerFrame
dstFormat.mBytesPerFrame = 2 * dstFormat.mChannelsPerFrame
dstFormat.mFramesPerPacket = 1
dstFormat.mFormatFlags = kAudioFormatFlagIsBigEndian |
kAudioFormatFlagIsSignedInteger
// Create destination file
error = ExtAudioFileCreateWithURL(
outputURL as CFURL,
kAudioFileAIFFType,
&dstFormat,
nil,
AudioFileFlags.eraseFile.rawValue,
&destinationFile)
reportError(error: error)
error = ExtAudioFileSetProperty(sourceFile!,
kExtAudioFileProperty_ClientDataFormat,
thePropertySize,
&dstFormat)
reportError(error: error)
error = ExtAudioFileSetProperty(destinationFile!,
kExtAudioFileProperty_ClientDataFormat,
thePropertySize,
&dstFormat)
reportError(error: error)
let bufferByteSize : UInt32 = 32768
var srcBuffer = [UInt8](repeating: 0, count: 32768)
var sourceFrameOffset : ULONG = 0
while(true){
var fillBufList = AudioBufferList(
mNumberBuffers: 1,
mBuffers: AudioBuffer(
mNumberChannels: 2,
mDataByteSize: UInt32(srcBuffer.count),
mData: &srcBuffer
)
)
var numFrames : UInt32 = 0
if(dstFormat.mBytesPerFrame > 0){
numFrames = bufferByteSize / dstFormat.mBytesPerFrame
}
error = ExtAudioFileRead(sourceFile!, &numFrames, &fillBufList)
reportError(error: error)
if(numFrames == 0){
error = noErr;
break;
}
sourceFrameOffset += numFrames
error = ExtAudioFileWrite(destinationFile!, numFrames, &fillBufList)
reportError(error: error)
}
error = ExtAudioFileDispose(destinationFile!)
reportError(error: error)
error = ExtAudioFileDispose(sourceFile!)
reportError(error: error)
}
Supporting method:
func reportError(error: OSStatus) {
// Handle error
}
Invocation:
let sourceUrl = URL(string: Bundle.main.path(forResource: "sample", ofType: "mp3")!)
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory,
.userDomainMask,
true)
let documentsDirectory = URL(string: paths.first!)
let destUrl = documentsDirectory?.appendingPathComponent("converted.aiff")
if let sourceUrl = sourceUrl, let destUrl = destUrl {
print("from \(sourceUrl.absoluteString) to \(destUrl.absoluteString)")
convertAudio(sourceUrl, outputURL: destUrl)
}
iOS Code to Convert m4a to WAV
If anyone else needs some code to do this here it is in Swift
func convertAudioFile(sourceURL: CFURLRef, destinationURL:
CFURLRef, outputFormat: OSType ,
outputSampleRate: Float64) -> OSStatus
{
var error : OSStatus = noErr
var destinationFile : ExtAudioFileRef = nil
var sourceFile : ExtAudioFileRef = nil
var srcFormat : AudioStreamBasicDescription = AudioStreamBasicDescription()
var dstFormat : AudioStreamBasicDescription = AudioStreamBasicDescription()
var audioConverter : AudioConverterRef = nil
audioConverter = AudioConverterRef.init()
ExtAudioFileOpenURL(sourceURL, &sourceFile)
var thePropertySize: UInt32 = UInt32(strideofValue(srcFormat))
ExtAudioFileGetProperty(sourceFile, kExtAudioFileProperty_FileDataFormat, &thePropertySize, &srcFormat)
dstFormat.mSampleRate = (outputSampleRate == 0 ? srcFormat.mSampleRate : outputSampleRate) //Set sample rate
dstFormat.mFormatID = outputFormat
dstFormat.mChannelsPerFrame = 1
dstFormat.mBitsPerChannel = 16
dstFormat.mBytesPerPacket = 2 * dstFormat.mChannelsPerFrame
dstFormat.mBytesPerFrame = 2 * dstFormat.mChannelsPerFrame
dstFormat.mFramesPerPacket = 1
dstFormat.mFormatFlags = kLinearPCMFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger // little-endian
//Create destination file
ExtAudioFileCreateWithURL(destinationURL, kAudioFileCAFType, &dstFormat, nil,
AudioFileFlags.EraseFile.rawValue, &destinationFile)
ExtAudioFileSetProperty(sourceFile, kExtAudioFileProperty_ClientDataFormat, thePropertySize, &dstFormat)
ExtAudioFileSetProperty(destinationFile, kExtAudioFileProperty_ClientDataFormat, thePropertySize, &dstFormat)
var size : UInt32 = UInt32(strideofValue(audioConverter))
ExtAudioFileGetProperty(destinationFile, kExtAudioFileProperty_AudioConverter, &size, &audioConverter)
var canResume : UInt32 = 0
size = UInt32(strideofValue(canResume))
error = AudioConverterGetProperty(audioConverter, kAudioConverterPropertyCanResumeFromInterruption, &size, &canResume)
let bufferByteSize : UInt32 = 32768
var srcBuffer = [UInt8](count: 32768, repeatedValue: 0)
var sourceFrameOffset : ULONG = 0
print("Converting audio file")
while(true){
var fillBufList = AudioBufferList(
mNumberBuffers: 1,
mBuffers: AudioBuffer(
mNumberChannels: 2,
mDataByteSize: UInt32(srcBuffer.count),
mData: &srcBuffer
)
)
var numFrames : UInt32 = 0
if(dstFormat.mBytesPerFrame > 0){
numFrames = bufferByteSize / dstFormat.mBytesPerFrame
}
ExtAudioFileRead(sourceFile, &numFrames, &fillBufList)
if(numFrames == 0){
error = noErr;
break;
}
sourceFrameOffset += numFrames
error = ExtAudioFileWrite(destinationFile, numFrames, &fillBufList)
}
ExtAudioFileDispose(destinationFile)
ExtAudioFileDispose(sourceFile)
let audioAsset = AVURLAsset.init(URL: destinationURL, options: nil)
if(audioAsset.duration.seconds < 5.0){
error = -2500
}
return error;
kAudioFormat for .aif audio file conversion?
I haven' worked with AVAssetWriter so far, but I assume its basically a format description as in Core Audio with ASBDs.
An example of a AudioBasicStreamDescription defined for AIFF see for example here:
aiffFormat.mSampleRate = sampleRate;
aiffFormat.mFormatID = kAudioFormatLinearPCM;
aiffFormat.mBytesPerPacket = 2;
aiffFormat.mFramesPerPacket = 1;
aiffFormat.mBytesPerFrame = 2;
aiffFormat.mChannelsPerFrame = 2; // for STEREO
aiffFormat.mBitsPerChannel = 16;
aiffFormat.mFormatFlags = (kLinearPCMFormatFlagIsBigEndian | kAudioFormatFlagIsPacked | kLinearPCMFormatFlagIsSignedInteger) ;
aiffFormat.mBitsPerChannel = sizeof(float) * 8;
aiffFormat.mBytesPerFrame = aiffFormat.mChannelsPerFrame * sizeof(Float32);
aiffFormat.mBytesPerPacket = aiffFormat.mFramesPerPacket * aiffFormat.mBytesPerFrame;
In your above code big endianess has to be set to YES. As mentioned I have never worked with AVAssetWriter, so I am not sure which further parameters have to be set or which not, but with the example stream description above, it should be not too hard to get running.
Reverse an audio file Swift/Objective-C
Yes, there is a way you can process, then export, any of the audio files for which there is iOS support.
However, most of these formats (mp3
to name one) are lossy and compressed. You must first decompress the data, apply the transformation, and recompress. Most transformation you will apply to the audio information should likely be done at the raw, PCM level.
Combining these two statements, you do this in a few passes:
- convert original file to a
kAudioFormatLinearPCM
compliant audio file, likeAIFF
- process that temporary file (reverse its content)
- convert the temporary file back to the original format
Just like if you were applying a transformation to, say, a compressed jpeg
image, there will be degradation in the process. The final audio will have, at best, suffered one more compression cycle.
So the true mathematical answer to this approach is actually no.
Just for reference, here is some starter code in swift 3. It needs further refinement to skip the file headers.
var outAudioFile:AudioFileID?
var pcm = AudioStreamBasicDescription(mSampleRate: 44100.0,
mFormatID: kAudioFormatLinearPCM,
mFormatFlags: kAudioFormatFlagIsBigEndian | kAudioFormatFlagIsSignedInteger,
mBytesPerPacket: 2,
mFramesPerPacket: 1,
mBytesPerFrame: 2,
mChannelsPerFrame: 1,
mBitsPerChannel: 16,
mReserved: 0)
var theErr = AudioFileCreateWithURL(destUrl as CFURL!,
kAudioFileAIFFType,
&pcm,
.eraseFile,
&outAudioFile)
if noErr == theErr, let outAudioFile = outAudioFile {
var inAudioFile:AudioFileID?
theErr = AudioFileOpenURL(sourceUrl as! CFURL, .readPermission, 0, &inAudioFile)
if noErr == theErr, let inAudioFile = inAudioFile {
var fileDataSize:UInt64 = 0
var thePropertySize:UInt32 = UInt32(MemoryLayout<UInt64>.stride)
theErr = AudioFileGetProperty(inAudioFile,
kAudioFilePropertyAudioDataByteCount,
&thePropertySize,
&fileDataSize)
if( noErr == theErr) {
let dataSize:Int64 = Int64(fileDataSize)
let theData = UnsafeMutableRawPointer.allocate(bytes: Int(dataSize),
alignedTo: MemoryLayout<UInt8>.alignment)
var readPoint:Int64 = Int64(dataSize)
var writePoint:Int64 = 0
while( readPoint > 0 )
{
var bytesToRead = UInt32(2)
AudioFileReadBytes( inAudioFile, false, readPoint, &bytesToRead, theData)
AudioFileWriteBytes( outAudioFile, false, writePoint, &bytesToRead, theData)
writePoint += 2
readPoint -= 2
}
theData.deallocate(bytes: Int(dataSize), alignedTo: MemoryLayout<UInt8>.alignment)
AudioFileClose(inAudioFile);
AudioFileClose(outAudioFile);
}
}
}
Trying to read AIFF Files Unexpected Error to do with pointer location etc
Your code doesn't appear to check to see if fopen()
returns NULL... so if fopen()
fails for whatever reason (most likely because the specified file doesn't exist or can't be opened for reading), then your program will crash when fread()
tries to dereference the NULL pointer.
Side note: since .AIFF files are binary files, not ASCII, you should be passing "rb" as the second argument to fopen()
rather than "r".
Related Topics
Use of Undeclared Type 'Viewcontroller' When Unit Testing My Own Viewcontroller in Swift
How to Make a Https Request to a Server in Swift
Swift Weak Reference Much Slower Than Strong Reference
How to Remove Numbers from a String in Swift
Is It the Right Way Using '[Weak Self]' in Swift Closure
How to Apply Borders and Corner Radius to Uibarbuttonitem
How Does Anyobject Conform to Nsobjectprotocol
How to Convert Int to Byte Array of 4 Bytes in Swift
Common Equatable Class on Swift
Binary Operator '===' Cannot Be Applied to Operands of Type 'Any' and 'Uibarbuttonitem!'
Convert Timestamp String with Epochal Time and Timezone into Nsdate
Evaluate Bool Property of Optional Object in If Statement
How to Block Users on Firebase in a Social Media App? for iOS
Adding a View to the Window Hierarchy