Convert PCM int16 to float32 iOS


What's inside this article ⌄
  • KMP IOS convert PCM int 16bit to PCM float 32bit
  • PCM int16 to float32 IOS
  • Kotlin Multiplatform PCM conversion
  • IOS audio format conversion KMP
  • Convert PCM audio format IOS

This code is for converting audio in ByteArray in PCM int 16bit mono format to audio in ABAudioPCMBuffer in PCM float 32bit stereo format:

 1fun convertMonoPCMInt16ToStereoPCMFloat32(
 2        inputData: ByteArray, inputSampleRate: Double, outputSampleRate: Double
 3    ): AVAudioPCMBuffer? {
 4        val inputFrameLength = inputData.size / 2  // 2 bytes per Int16 sample
 5        val resampleRatio = outputSampleRate / inputSampleRate
 6        val outputFrameLength = (inputFrameLength * resampleRatio).toInt()
 7
 8        val audioFormat = AVAudioFormat(standardFormatWithSampleRate = outputSampleRate, channels = 2u)
 9        val outputBuffer = AVAudioPCMBuffer(audioFormat, frameCapacity = outputFrameLength.toUInt()) ?: return null
10
11        val leftChannel = outputBuffer.floatChannelData!![0]
12        val rightChannel = outputBuffer.floatChannelData!![1]
13
14        for (outputFrame in 0 until outputFrameLength) {
15            val inputFrameFloat = outputFrame / resampleRatio
16            val inputFrame = inputFrameFloat.toInt()
17            val fraction = inputFrameFloat - inputFrame
18
19            val sample1 = readInt16Sample(inputData, inputFrame, inputFrameLength)
20            val sample2 = readInt16Sample(inputData, inputFrame + 1, inputFrameLength)
21            val interpolatedSample = (1 - fraction) * sample1 + fraction * sample2
22
23            // Convert to Float and apply gain control
24            val floatSample = (interpolatedSample / Short.MAX_VALUE.toFloat()) * 0.7f  // Apply -3dB attenuation
25
26            // Duplicate to stereo
27            leftChannel!![outputFrame] = floatSample.toFloat()
28            rightChannel!![outputFrame] = floatSample.toFloat()
29        }
30
31        outputBuffer.frameLength = outputFrameLength.toUInt()
32        return outputBuffer
33    }
34
35    private fun readInt16Sample(inputData: ByteArray, index: Int, length: Int): Int {
36        if (index >= length) return 0
37        val low = inputData[index * 2].toInt() and 0xFF
38        val high = inputData[index * 2 + 1].toInt()
39        return (high shl 8) or low
40    }
41}