How to decode using lame (mp3->wav) in c++

2

Thank you so much for answering this question.

I use lame and I want to decode mp3 file to wav.

I succeeded in decoding mp3 files into wav files through several searches. However, the size of the wav file is created too large and an error message appears. Media player error message : This file cannot be played. The file format may not be supported, the file extension may be incorrect, or the file may be corrupted.

If you know my problem, please give me some advice. Thank you

HEADER FILE

#pragma once
#ifndef _LAME_HELPER_H_
#define _LAME_HELPER_H_

#include <windows.h>
#include "lame.h"

#define LH_STARTED WM_USER+1
#define LH_COMPUTED WM_USER+2
#define LH_DONE WM_USER+3
#define LH_ERROR WM_USER+4

#define MAX_THREAD_COUNT 5

enum encode_mode_e
{
    EM_ABR,
    EM_CBR,
    EM_VBR
};

enum encode_channel_e
{
    EC_MONO,
    EC_STEREO
};

enum bitrate_e
{
    BR_8kbps = 8,
    BR_16kbps = 16,
    BR_24kbps = 24,
    BR_32kbps = 32,
    BR_40kbps = 40,
    BR_48kbps = 48,
    BR_56kbps = 56,
    BR_64kbps = 64,
    BR_80kbps = 80,
    BR_96kbps = 96,
    BR_112kbps = 112,
    BR_128kbps = 128,
    BR_144kbps = 144,
    BR_160kbps = 160,
    BR_192kbps = 192,
    BR_224kbps = 224,
    BR_256kbps = 256,
    BR_320kbps = 320
};

enum samplerate_e
{
    SR_8khz = 8000,
    SR_11khz = 11025,
    SR_12khz = 12000,
    SR_16khz = 16000,
    SR_22khz = 22050,
    SR_24khz = 24000,
    SR_32khz = 32000,
    SR_44khz = 44100,
    SR_48khz = 48000
};

struct settings_t
{
    char* title;
    char* artist;
    char* album;
    char* comment;
    char* year;
    char* track;
    char* genre;
    char* albumart;

    encode_channel_e channels;
    bitrate_e abr_bitrate;
    bitrate_e cbr_bitrate;
    int quality;
    encode_mode_e enc_mode;
    samplerate_e resample_frequency;
    samplerate_e in_samplerate;

    //The constructor; used to set default values
    settings_t();
};

class CLameHelper; //lameHelper prototype, needed because of struct StaticParam_t

//Use to hold parameters for the thread function
struct StaticParam_t
{
    char* pcm;
    char* mp3;
    settings_t settings;
    WNDPROC callback_proc;
    CLameHelper* lhObj;
};


class CLameHelper
{
public :
    static const int PCM_SIZE = 4096;
    static const int MP3_SIZE = 4096;

    HANDLE m_hThread[MAX_THREAD_COUNT];
    StaticParam_t* m_phSParam[MAX_THREAD_COUNT];

    static int Decode_s(void* pParam);
    
    void WriteWaveHeader(FILE* const, int, int, int, int);
    void Write32BitLowHigh(FILE*, int);
    void Write16BitLowHigh(FILE*, int);

    int SetID3AlbumArt(lame_t gfp, char const* szFileName);
    void errorHandler(char*);
    char errMsg[1000];

public:
    CLameHelper();
    ~CLameHelper();

    int Decode(char* szMp3_in, char* szPcm_out);
    int Decode(char* szMp3_in, char* szPcm_out, WNDPROC callback_proc); 
};

#endif

CPP FILE

#include "stdafx.h"
#include "LameHelper.h"

settings_t::settings_t()
{
    //Setting the default values
    title = "";
    artist = "";
    album = "";
    comment = "";
    year = "";
    track = "";
    genre = "";
    albumart = NULL;
    
    channels = EC_STEREO;
    abr_bitrate = BR_128kbps;
    cbr_bitrate = BR_128kbps;
    quality = 5;
    enc_mode = EM_CBR;
    resample_frequency = SR_44khz; 
    in_samplerate = SR_44khz;
}


CLameHelper::CLameHelper()
{
    //Initialize to NULL, aids deletion/closing later
    for(int i = 0; i < MAX_THREAD_COUNT; i++)
    {
        m_hThread[i] = NULL;
        m_phSParam[i] = NULL;
    }
    
}

CLameHelper::~CLameHelper()
{
    //Destroy all declared objects
    for(int i = 0; i < MAX_THREAD_COUNT; i++)
    {
        if(m_hThread[i] != NULL)
            CloseHandle(m_hThread[i]);

        if(m_phSParam[i] != NULL)
            delete m_phSParam[i];
    }
}


int CLameHelper::SetID3AlbumArt(lame_t gfp, char const* szFileName)
{
    int iResult = -1;
    FILE *pFileName = 0;
    char *szAlbumart = 0;

    if(szFileName == NULL) 
    {
        return 0;
    }

    pFileName = fopen(szFileName, "rb");

    if(!pFileName) 
    {
        iResult = 1;
    }
    else
    {
        size_t size;

        fseek(pFileName, 0, SEEK_END);
        size = ftell(pFileName);
        fseek(pFileName, 0, SEEK_SET);
        szAlbumart = (char*)malloc(size);
        if(!szAlbumart)
        {
            iResult = 2;            
        }
        else 
        {
            if(fread(szAlbumart, 1, size, pFileName) != size)
            {
                iResult = 3;
            }
            else 
            {
                iResult = (gfp, szAlbumart, size) ? 4 : 0;
            }
            free(szAlbumart);
        }
        fclose(pFileName);
    }
    switch(iResult)
    {
    case 1:
        sprintf(errMsg, "WARNING: could not find file '%s' for szAlbumart.\n", szFileName);
        errorHandler(errMsg); 
        break;
    case 2:
        errorHandler("WARNING: insufficient memory for reading the szAlbumart.\n");
        break;
    case 3:
        sprintf(errMsg, "WARNING: read error in '%s' for szAlbumart.\n", szFileName);
        errorHandler(errMsg);
        break;
    case 4: 
        sprintf(errMsg, "WARNING: unsupported image: '%s' for szAlbumart. Specify JPEG/PNG/GIF image\n", szFileName);
        errorHandler(errMsg);
        break;
    default: 
        break;
    }
    return iResult;
}


void CLameHelper::Write16BitLowHigh(FILE * fp, int val)
{
    unsigned char bytes[2];
    bytes[0] = (val & 0xff);
    bytes[1] = ((val >> 8) & 0xff);
    fwrite(bytes, 1, 2, fp);
}

void CLameHelper::Write32BitLowHigh(FILE * fp, int val)
{
    unsigned char bytes[4];
    bytes[0] = (val & 0xff);
    bytes[1] = ((val >> 8) & 0xff);
    bytes[2] = ((val >> 16) & 0xff);
    bytes[3] = ((val >> 24) & 0xff);
    fwrite(bytes, 1, 4, fp);
}

void CLameHelper::WriteWaveHeader(FILE * const fp, int pcmbytes, int freq, int channels, int bits)
{
    int     bytes = (bits + 7) / 8;
    /* quick and dirty, but documented */
    fwrite("RIFF", 1, 4, fp); /* label */
    Write32BitLowHigh(fp, pcmbytes + 44 - 8); /* length in bytes without header */
    fwrite("WAVEfmt ", 2, 4, fp); /* 2 labels */
    Write32BitLowHigh(fp, 2 + 2 + 4 + 4 + 2 + 2); /* length of PCM format declaration area */
    Write16BitLowHigh(fp, 1); /* is PCM? */
    Write16BitLowHigh(fp, channels); /* number of channels */
    Write32BitLowHigh(fp, freq); /* sample frequency in [Hz] */
    Write32BitLowHigh(fp, freq * channels * bytes); /* bytes per second */
    Write16BitLowHigh(fp, channels * bytes); /* bytes per sample time */
    Write16BitLowHigh(fp, bits); /* bits per sample */
    fwrite("data", 1, 4, fp); /* label */
    Write32BitLowHigh(fp, pcmbytes); /* length in bytes of raw PCM data */
}

int CLameHelper::Decode(char* szMp3_in, char* szPcm_out)
{
    return Decode(szMp3_in, szPcm_out, NULL);
}

//the static function used for the thread
int CLameHelper::Decode_s(void* param)
{
    StaticParam_t* sp = (StaticParam_t*)param;
    char* szPcm_out = sp->pcm;
    char* szMp3_in = sp->mp3;
    WNDPROC callback_proc = sp->callback_proc;

    CLameHelper* lh = (CLameHelper*)sp->lhObj;
    return lh->Decode(szMp3_in, szPcm_out, callback_proc);
}


int CLameHelper::Decode(char* szMp3_in, char* szPcm_out, WNDPROC callback_proc)
{
    int read, i, samples;
    long wavsize = 0; // use to count the number of mp3 byte read, this is used to write the length of the wave file
    long cumulative_read = 0;

    short int pcm_l[PCM_SIZE], pcm_r[PCM_SIZE];
    unsigned char mp3_buffer[MP3_SIZE];

    FILE* mp3 = fopen(szMp3_in, "rb");
    if(mp3 == NULL)
    {
        if(callback_proc != NULL)
        {
            callback_proc((HWND)GetModuleHandle(NULL), LH_ERROR, -1, NULL);
        }
        sprintf(errMsg, "FATAL ERROR: file '%s' can't be open for read. Aborting!\n", szMp3_in);
        errorHandler(errMsg);
        return -1;
    }
    fseek(mp3, 0, SEEK_END);
    long MP3_total_size = ftell(mp3);
    fseek(mp3, 0, SEEK_SET);

    
    FILE* pcm = fopen(szPcm_out, "wb");
    if(pcm == NULL)
    {
        if(callback_proc != NULL)
        {
            callback_proc((HWND)GetModuleHandle(NULL), LH_ERROR, -1, NULL);
        }
        sprintf(errMsg, "FATAL ERROR: file '%s' can't be open for write. Aborting!\n", szPcm_out);
        errorHandler(errMsg);
        return -1;
    }

    
    lame_t lame = lame_init();
    lame_set_decode_only(lame, 1);
    if(lame_init_params(lame) == -1)
    {
        if(callback_proc != NULL)
        {
            callback_proc((HWND)GetModuleHandle(NULL), LH_ERROR, -2, NULL);
        }
        sprintf(errMsg, "FATAL ERROR: parameters failed to initialize properly in lame. Aborting!\n", szPcm_out);
        errorHandler(errMsg);
        return -2;
    }

    hip_t hip = hip_decode_init();
    
    mp3data_struct mp3data;
    memset(&mp3data, 0, sizeof(mp3data));
    
    int nChannels = -1;
    int nSampleRate = -1;
    int mp3_len;

    if(callback_proc != NULL)
    {
        callback_proc((HWND)GetModuleHandle(NULL), LH_STARTED, NULL, NULL);
    }

    while((read = fread(mp3_buffer, sizeof(char), MP3_SIZE, mp3)) > 0)
    {
        mp3_len = read;
        cumulative_read += read * sizeof(char);
        do
        {
            samples = hip_decode1_headers(hip, mp3_buffer, mp3_len, pcm_l, pcm_r, &mp3data);
            wavsize += samples;

            if(mp3data.header_parsed == 1)//header is gotten
            {
                if(nChannels < 0)//reading for the first time
                {
                    //Write the header
                    WriteWaveHeader(pcm, 0x7FFFFFFF, mp3data.samplerate, mp3data.stereo, 16); //unknown size, so write maximum 32 bit signed value
                }
                nChannels = mp3data.stereo;
                nSampleRate = mp3data.samplerate;
            }

            if(samples > 0 && mp3data.header_parsed != 1)
            {
                errorHandler("WARNING: lame decode error occured!");
                break;
            }

            if(samples > 0)
            {
                for(i = 0 ; i < samples; i++)
                {
                    fwrite((char*)&pcm_l[i], sizeof(char), sizeof(pcm_l[i]), pcm);
                    if(nChannels == 2)
                    {
                        fwrite((char*)&pcm_r[i], sizeof(char), sizeof(pcm_r[i]), pcm);
                    }
                }
            }
            mp3_len = 0;

            if(callback_proc != NULL)
            {
                int percentage = ((float)cumulative_read/MP3_total_size)*100;
                callback_proc((HWND)GetModuleHandle(NULL), LH_COMPUTED, percentage, NULL);
            }
        }while(samples>0);
    }

    i = (16 / 8) * mp3data.stereo;
    if (wavsize <= 0) 
    {
       wavsize = 0;
    }
    else if (wavsize > 0xFFFFFFD0 / i) 
    {
        wavsize = 0xFFFFFFD0;
    }
    else 
    {
        wavsize *= i;
    }
    
    if(!fseek(pcm, 0l, SEEK_SET))//seek back and adjust length
        WriteWaveHeader(pcm, (int) wavsize, mp3data.samplerate, mp3data.stereo, 16);
    else
        errorHandler("WARNING: can't seek back to adjust length in wave header!");

    hip_decode_exit(hip);
    lame_close(lame);
    fclose(mp3);
    fclose(pcm);

    if(callback_proc != NULL)
    {
        callback_proc((HWND)GetModuleHandle(NULL), LH_DONE, NULL, NULL);
    }
    return 0;
}

void CLameHelper::errorHandler(char* msg)
{
    printf("%s\n", msg);
}
c++
decode
lame
asked on Stack Overflow Mar 19, 2021 by Jungwon • edited Mar 22, 2021 by Jungwon

1 Answer

0

I want to decode mp3 to PCM using lame. The problem I am having is

samples = hip_decode1_headers (hip, mp3_buffer, mp3_len, pcm_l, pcm_r, & mp3data);

always returns 0.

The mp3_buffer I passed has removed the ID3 tag, and it contains about 8 mp3 frames.

answered on Stack Overflow Apr 5, 2021 by Hung Hero • edited Apr 5, 2021 by L_J

User contributions licensed under CC BY-SA 3.0