Comments (13)
Certainly, @tryWabbit! Converting an M4A file to MP3 involves a few steps. I'll explain in detail:
-
Decode the M4A File: You need to decode the M4A audio data into raw PCM audio data. M4A is a compressed audio format, and you should decompress it before encoding it to MP3. You can use a library like FFmpeg or AVFoundation in Swift to do this. You'll end up with PCM audio data, which is uncompressed. Convert m4a to WAV
-
Encode to MP3: Once you have the raw PCM audio data, you can encode it to MP3. LAME is a popular library for encoding audio to MP3 format. Make sure you're passing the raw audio data (uncompressed) to LAME for encoding. AudioConverter.swift
-
Set Appropriate MP3 Parameters: When encoding to MP3, you can set various parameters like bitrate, sample rate, and quality. Adjust these parameters according to your needs. Higher bitrates typically result in better audio quality but larger file sizes. AudioConverter.swift
-
Save the MP3 File: Finally, save the encoded MP3 audio to a file. Make sure you provide a valid file path for the output.
Thanks!
from lame.
Thank you so much @pro100andrey the mistake I did was I put the lame_set_num_channels(lame, 1)
after the lame_init_params(lame)
.
Really appreciate your help : )
from lame.
Hi @tryWabbit, You are not decoding the M4A audio into raw audio data before sending it into LAME.
"PCM audio" means no compression.
from lame.
Thanks for the quick reply @pro100andrey ! I have limited experience with audio conversions. Can you explain me in detail what updates I need to make to get an mp3 file out of a m4a file. Really appreaciate your help!
from lame.
If you're recording audio directly from a microphone and want to save it in MP3 format, you can use the LAME library to convert PCM audio to MP3 on the fly. LAME provides the capability to encode audio into MP3 format while recording or streaming.
For example AURenderCallback
from lame.
Thank you so much for the detailed explanation @pro100andrey Really appreciate your help! I will try and update you
from lame.
Hey @pro100andrey I tried your solution and it worked! The only problem I have right now is the converted audio is half of the size and playing like it's in fast forward. I'm sure there is a difference between the configuration I'm converting it in and your configs for conversion. Can you verify?
Method I'm using to convert m4a to wav. The output is fine and match the audio.
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 = kLinearPCMFormatFlagIsPacked |
kAudioFormatFlagIsSignedInteger
// Create destination file
error = ExtAudioFileCreateWithURL(
outputURL as CFURL,
kAudioFileWAVEType,
&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)
}
Your method of conversion from wav to mp3
class func encodeToMp3(
inPcmPath: String,
outMp3Path: String,
onProgress: @escaping (Float) -> (Void),
onComplete: @escaping () -> (Void)
) {
encoderQueue.async {
let lame = lame_init()
lame_set_in_samplerate(lame, 44100)
lame_set_out_samplerate(lame, 0)
lame_set_brate(lame, 0)
lame_set_quality(lame, 4)
lame_set_VBR(lame, vbr_off)
lame_init_params(lame)
let pcmFile: UnsafeMutablePointer<FILE> = fopen(inPcmPath, "rb")
fseek(pcmFile, 0 , SEEK_END)
let fileSize = ftell(pcmFile)
// Skip file header.
let pcmHeaderSize = 48 * 8
fseek(pcmFile, pcmHeaderSize, SEEK_SET)
let mp3File: UnsafeMutablePointer<FILE> = fopen(outMp3Path, "wb")
let pcmSize = 1024 * 8
let pcmbuffer = UnsafeMutablePointer<Int16>.allocate(capacity: Int(pcmSize * 2))
let mp3Size: Int32 = 1024 * 8
let mp3buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: Int(mp3Size))
var write: Int32 = 0
var read = 0
repeat {
let size = MemoryLayout<Int16>.size * 2
read = fread(pcmbuffer, size, pcmSize, pcmFile)
// Progress
if read != 0 {
let progress = Float(ftell(pcmFile)) / Float(fileSize)
DispatchQueue.main.sync { onProgress(progress) }
}
if read == 0 {
write = lame_encode_flush_nogap(lame, mp3buffer, mp3Size)
} else {
write = lame_encode_buffer_interleaved(lame, pcmbuffer, Int32(read), mp3buffer, mp3Size)
}
fwrite(mp3buffer, Int(write), 1, mp3File)
} while read != 0
// Clean up
lame_close(lame)
fclose(mp3File)
fclose(pcmFile)
pcmbuffer.deallocate()
mp3buffer.deallocate()
DispatchQueue.main.sync { onComplete() }
}
}
Can you identify the difference in conversion which is causing the audio to be fast the half of the actual duration ?
Thanks
from lame.
Hi, @tryWabbit, if your file contains 1 channel, try set lame_set_num_channels to 1
/* number of channels in input stream. default=2 */
int CDECL lame_set_num_channels(lame_global_flags *, int);
from lame.
@tryWabbit
I noticed that you can improve your code. You can combine the two functions func convertAudio(_ url:, outputURL:)
and func encodeToMp3(inPcmPath:, outMp3Path:, onProgress:, onComplete:)
into one. After ExtAudioFileRead(sourceFile!, &numFrames, &fillBufList)
, you can directly write fillBufList
to MP3 without intermediate saving to a WAV file.
Think about it :).
from lame.
Hi, @tryWabbit, if your file contains 1 channel, try set lame_set_num_channels to 1
/* number of channels in input stream. default=2 */ int CDECL lame_set_num_channels(lame_global_flags *, int);
I set the number of channels to 1 by lame_set_num_channels(lame, 1)
but it is still generating audio which is having half of the duration and fast playing
I'm sorry if I don't make sense I don't have any experience with lame and c apis and have limited experience with audio apis for ios.
from lame.
@tryWabbit I noticed that you can improve your code. You can combine the two functions
func convertAudio(_ url:, outputURL:)
andfunc encodeToMp3(inPcmPath:, outMp3Path:, onProgress:, onComplete:)
into one. AfterExtAudioFileRead(sourceFile!, &numFrames, &fillBufList)
, you can directly writefillBufList
to MP3 without intermediate saving to a WAV file.Think about it :).
Thank you so much for suggesting that. I will definitely focus on this once I get it working.
from lame.
I uploaded a testing project on which I'm doing the experiment here in case you want to see the issue - https://github.com/tryWabbit/Audio-Conversion
from lame.
@tryWabbit result without issue (replaced lame_encode_buffer_interleaved
with lame_encode_buffer
with empty right channel.)
//
// AudioConverter.swift
// Example
//
// Created by Andrey on 20.11.2020.
//
import Foundation
import lame
class AudioConverter {
private static let encoderQueue = DispatchQueue(label: "com.audio.encoder.queue")
class func encodeToMp3(
inPcmPath: String,
outMp3Path: String,
onProgress: @escaping (Float) -> (Void),
onComplete: @escaping () -> (Void)
) {
encoderQueue.async {
let numOfChannels: Int32 = 1
let lame = lame_init()
lame_set_in_samplerate(lame, 44100)
lame_set_out_samplerate(lame, 0)
lame_set_brate(lame, 0)
lame_set_quality(lame, 4)
lame_set_VBR(lame, vbr_off)
lame_set_num_channels(lame, numOfChannels)
lame_init_params(lame)
let pcmFile: UnsafeMutablePointer<FILE> = fopen(inPcmPath, "rb")
fseek(pcmFile, 0 , SEEK_END)
let fileSize = ftell(pcmFile)
// Skip file header.
let pcmHeaderSize = 48 * 8
fseek(pcmFile, pcmHeaderSize, SEEK_SET)
let mp3File: UnsafeMutablePointer<FILE> = fopen(outMp3Path, "wb")
let pcmSize = 1024 * 8
let pcmbuffer = UnsafeMutablePointer<Int16>.allocate(capacity: Int(pcmSize * 2))
let mp3Size: Int32 = 1024 * 8
let mp3buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: Int(mp3Size))
var write: Int32 = 0
var read = 0
repeat {
let size = MemoryLayout<Int16>.size * Int(numOfChannels)
read = fread(pcmbuffer, size, pcmSize, pcmFile)
// Progress
if read != 0 {
let progress = Float(ftell(pcmFile)) / Float(fileSize)
DispatchQueue.main.sync { onProgress(progress) }
}
if read == 0 {
write = lame_encode_flush_nogap(lame, mp3buffer, mp3Size)
} else {
write = lame_encode_buffer(lame, pcmbuffer, [] ,Int32(read), mp3buffer, mp3Size)
}
fwrite(mp3buffer, Int(write), 1, mp3File)
} while read != 0
// Clean up
lame_close(lame)
fclose(mp3File)
fclose(pcmFile)
pcmbuffer.deallocate()
mp3buffer.deallocate()
DispatchQueue.main.sync { onComplete() }
}
}
}
from lame.
Related Issues (12)
- Type cast HOT 4
- Compilation warnings HOT 1
- Any Plan Support For Apple Privacy Manifest? HOT 3
- Issue with i386 HOT 3
- M1 Macbook Pro: wrong architecture HOT 2
- swift version? HOT 1
- lame issue HOT 1
- Encode is removing silence HOT 1
- mp3 file full with noise HOT 2
- Support for arm64 based simulators HOT 3
- maccatalyst: Framework not found HOT 2
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from lame.