Sergei Gorbunov
Sergei Gorbunov

Reputation: 11

Converting pcm to mp3 (using LAME) causes "clicks" in mp3 file

My app using LAME to encode raw pcm data to mp3. But i have a problem - output mp3 contains "clicks" in persistent period of time. Something like that:

sound... "click" sound.. "click" sound.. "click" etc...

I have tried different versions of LAME and tried change many LAME settings but not succeed. My app also can convert pcm to wav and ogg, but this converters do not results that "clicks".

There is a encoding code (pcm input contains one channel data, pcm already resampled to 44100 freq):

Initialization:

lame = lame_init();
lame_set_in_samplerate(lame, 44100);
lame_set_VBR(lame, vbr_abr);//vbr_default
lame_init_params(lame);

//Samples count (do not have any effect on output)
dwSamples=1024;

//mp3 buffer size, if it do not equals dwSamples*2 than output sound getting scaled
dwMP3Buffer=dwSamples*2;

pMP3Buffer = new BYTE[dwMP3Buffer];

Writing pcm data

int Mp3Stream :: Write(short * _data, int _size)
{
    if (_size > 0)
    {
        for(int curPos = 0; curPos < _size; curPos += dwMP3Buffer)
        {
            //int size = dwMP3Buffer;

            //if (_size - curPos < dwMP3Buffer)
            //  size = _size - curPos;

            int bytes = lame_encode_buffer(lame, (short *)((char *)_data + curPos), (short *)((char *)_data + curPos), dwSamples, pMP3Buffer, 0);

            IPF_TRACE(1, "MP3 encoder wrote "<<bytes<<" bytes");

            if (bytes<0)
            {
                IPF_TRACE(1, "MP3 encoding failed with code "<<bytes);
                return bytes;
            }

            BOOL bResult = WriteFile(hFile, pMP3Buffer, bytes, &bw, NULL);

            if (!bResult || bytes != bw)
            {
                IPF_TRACE(1, "MP3 write to file failed with code "<<bytes);
            }
        };
    }
}

Finalizing

int bytes = lame_encode_flush(lame, pMP3Buffer, 0);
    if (bytes<0)
{
    IPF_TRACE(1, "MP3 flush failed with code "<<bytes);
}
BOOL bResult = WriteFile(hFile, pMP3Buffer, bytes, &bw, NULL);
if (!bResult || bytes != bw)
{
    IPF_TRACE(1, "MP3 write to file failed with code "<<bytes);
}
int ret = lame_close(lame);
if (ret < 0) 
{
    IPF_TRACE(1, "MP3 lame close failed with code "<<ret);
}
delete []pMP3Buffer;

Upvotes: 1

Views: 5376

Answers (3)

Ravindhiran
Ravindhiran

Reputation: 5384

Try this,

void AQRecorder::MyInputBufferHandler(  void *                              inUserData,
                                AudioQueueRef                       inAQ,
                                AudioQueueBufferRef                 inBuffer,
                                const AudioTimeStamp *              inStartTime,
                                UInt32                              inNumPackets,
                                const AudioStreamPacketDescription* inPacketDesc)
{
AQRecorder *aqr = (AQRecorder *)inUserData;
//    NSLog(@"%f",inStartTime->mSampleTime);
try
{
    if (inNumPackets > 0)
    {
        AudioFileWritePackets(aqr->mRecordFile, FALSE, inBuffer->mAudioDataByteSize, inPacketDesc, aqr->mRecordPacket, &inNumPackets, inBuffer->mAudioData);

        aqr->mRecordPacket += inNumPackets;

        int MP3_SIZE =inBuffer->mAudioDataByteSize * 4;
        unsigned char mp3_buffer[MP3_SIZE];
        AppDelegate *delegate =[[UIApplication sharedApplication]delegate];
        lame_t lame = lame_init();
        lame_set_in_samplerate(lame, 44100);
        lame_set_VBR(lame, vbr_default);
        lame_init_params(lame);

  //                int encodedBytes=lame_encode_buffer_interleaved(lame, (short int *)inBuffer->mAudioData , inNumPackets, mp3_buffer, MP3_SIZE);


        int encodedBytes = lame_encode_buffer(lame, (short*)inBuffer->mAudioData,  (short*)inBuffer->mAudioData, inNumPackets, mp3_buffer, MP3_SIZE);

        [delegate.mp3AudioData appendBytes:mp3_buffer length:encodedBytes];

        if (inBuffer->mAudioDataByteSize != 0) {
        }
        else
        {
            int encode=lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
            [delegate.mp3AudioData appendBytes:mp3_buffer length:encode];
        }
        lame_close(lame);
    }

    if (aqr->IsRunning())
    {
        AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL);
    }
 } catch (CAXException e)
 {
 char buf[256];
 fprintf(stderr, "Error: %s (%s)\n", e.mOperation, e.FormatError(buf));
}
}

Upvotes: 1

rusxg
rusxg

Reputation: 98

I would try to set

dwSamples = 1152

1152 - is the audio frame size (in samples) for MPEG1Audio encoder. It looks like LAME processes data by frame-multiple chunks

Upvotes: 0

nvuono
nvuono

Reputation: 3363

The Sound -> Click -> Sound -> Click pattern most likely means you are only writing half of your buffer at a time and the other half is remaining zero'd out for each loop inside the Write call.

The reason for this is that your loop incrementer is based on the dwMP3Buffer value of dwSamples*2.

 for(int curPos = 0; curPos < _size; curPos += dwMP3Buffer){

This means you aren't actually encoding all of your input values since dwMP3Buffer is twice the number of samples you actually pass to the lame_encode_buffer call (dwSamples).

lame_encode_buffer(lame, (short *)((char *)_data + curPos), 
                   (short *)((char *)_data + curPos), dwSamples, pMP3Buffer, 0);

Try changing the loop incrementer to the following:

 for(int curPos = 0; curPos < _size; curPos += dwSamples){

Upvotes: 1

Related Questions