Glenncito
Glenncito

Reputation: 930

Coverting raw PCM file to MP3 with LAME returns distorted audio

I have raw PCM files generated from a base64 string. Here is the link to the API response that returns in..

I then create a PCM file from this string, after which I convert it to MP3 using the LAME library.

Here is the code that deals with the conversion:

    companion object {
  init {
      System.loadLibrary("mp3lame")
  }
  }


private external fun initEncoder(numChannels: Int, sampleRate: Int, bitRate: Int, mode: Int, quality: Int)
private external fun destroyEncoder()
private external fun encodeFile(sourcePath: String, targetPath: String): Int
val NUM_CHANNELS = 1
val SAMPLE_RATE = 16000
val BITRATE = 128
val MODE = 3
val QUALITY = 0

fun createAudioFromBase64AndGetPath(inputBase64: String, outputFileName: String) {
    initEncoder(NUM_CHANNELS, SAMPLE_RATE, BITRATE, MODE, QUALITY)

    val path: String = "newFile.wav"

    try {
        val decoded = Base64.decode(inputBase64, Base64.NO_WRAP)
        try {
            val fileRaw = File(Environment.getExternalStorageDirectory().toString() + "/$outputFileName.pcm")
            val fileEncoded = File(Environment.getExternalStorageDirectory().toString() + "/$outputFileName.mp3")


                val os = FileOutputStream(fileRaw, true)
                os.write(decoded)
                os.close()

            val result = encodeFile(fileRaw!!.absolutePath, fileEncoded!!.absolutePath)
            if (result == 0) {
                Log.d ("encoded to ", fileEncoded!!.name)
            }
            destroyEncoder()

        } catch (e: Exception) {
            Log.e ("decode ", "first catch", e)
            e.printStackTrace()
        }

    } catch (e: Exception) {
        e.printStackTrace()
        Log.d ("decode ", "2nd catch", e)
    }
}

The audio comes out sounding like this.

I've tried navigating the C library files that explain what the different variable options for initEncoder mean and I've fiddled around but nothing changes.

To try to troubleshoot this without the lag of compiling the app each time, I took the base64 string and converted it to a PCM file using an online converter (Motobit). I then used a very nifty (and free) converter for mac called XLD to test these conversions without having to compile the app each time to see if I could figure out what was going on, and if perhaps I was just using the wrong combination of variables for initEncoder.

The first thing I noticed was that I had to select the 'Open raw PCM (bin+cue)...' option in order to open the pcm filed downloaded from motobit.

Here is the selection window. The selection window

The next piece of the puzzle, which seems to be the crucial piece, was that I was only able to convert the audio properly (without the noise) when selecting "Little" in the Endian box. The problem is that back in my app, I am unable to find out how or if I even can access and change this property in the LAME library.

For clarity, I'm using the wrapper from here: https://developer.samsung.com/technical-doc/view.do?v=T000000090

Upvotes: 0

Views: 592

Answers (1)

greeble31
greeble31

Reputation: 5042

If you get desperate, you can always switch the endianness yourself:

for (i in decoded.indices step 2)
{
    val swap = decoded[i]
    decoded[i] = decoded[i + 1]
    decoded[i + 1] = swap
}

...since Base64.decode() returns a byte array, and I'm assuming you're using 16-bit audio.

I couldn't find the initEncoder() docs, myself.

Upvotes: 1

Related Questions