如何在C中将PCM 8kHz 8bit unsigned转换为mp3

时间:2015-10-29 00:39:29

标签: c mono mp3 pcm lame

我在与编程音频处理相关的主题方面完全是菜鸟,但我想将PCM音频数据转换为MP3。

我的音频采用PCM格式,频率为8kHz,位宽为8,字节类型为无符号,通道为单声道。

我正在使用liblamemp3,我通过执行以下命令行找到了lame.exe前端的方法:

$ ./lame -r -s 8 --bitwidth 8 --unsigned -m m ../../../../voice8K16bitmono.pcm output.mp3

结果是一个我能听得很清楚的.mp3。 (经过一些尝试)。

问题在于我想在运行中执行此操作,因此我尝试编写一些源代码来执行此操作而不调用前端。

我的源代码是:

#include <stdio.h>
#include <lame/lame.h>

int main(int argc, char *argv[])
{
    int read, write;

    FILE *pcm = fopen(argv[1], "rb");
    FILE *mp3 = fopen("file.mp3", "wb");

    const int PCM_SIZE = 8192;
    const int MP3_SIZE = 8192;

    unsigned short pcm_buffer;
    unsigned short pcm_buffer_le;
    unsigned char mp3_buffer[MP3_SIZE];

    lame_t lame = lame_init();
    lame_set_num_samples(lame, 8000);
    lame_set_in_samplerate(lame, 8000);
    lame_set_out_samplerate(lame, 8000);
    lame_set_num_channels(lame, 1);
    lame_set_mode(lame, 3);
    lame_init_params(lame);
    lame_print_config(lame);
    //framesize is bits / channels = 8.
    do {
        read = fread(&pcm_buffer, sizeof(short), 1, pcm);
    pcm_buffer = (pcm_buffer>>8) | (pcm_buffer<<8);
    if (read == 0) {
            write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
            fwrite(mp3_buffer, sizeof(char), write, mp3);
        break;
    }
    //pcm_buffer_le[0] = (pcm_buffer[0]>>8) | (pcm_buffer[0]<<8);
        write = lame_encode_buffer_interleaved(lame, &pcm_buffer, sizeof(short), mp3_buffer, MP3_SIZE);
        fwrite(mp3_buffer, sizeof(char), write, mp3);
    } while (1);

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

    return 0;
}

我从一个例子中取出它,并尝试应用我需要的设置。但是由此产生的.mp3听起来像一个反应堆而且听起来并不好。所以我错过了一些/很多代码。

我想这样做,所以,有人可以帮忙吗?

提前致谢。

1 个答案:

答案 0 :(得分:1)

  1. 每个样本只有1个字节,所以不应该读入sizeof(short)个字节,而应该读取1个字节。
  2. 您必须将无符号8位PCM样本转换为带符号的16位PCM样本(reference)。
  3. 由于输入是单声道,因此请使用lame_encode_buffer()代替lame_encode_buffer_interleaved(),并将buffer_r参数设置为NULLreference)。
  4. 以下是代码的修改后的工作版本:

    #include <stdio.h>
    #include <lame/lame.h>
    
    int main(int argc, char *argv[])
    {
        int read, write;
    
        FILE *pcm = fopen(argv[1], "rb");
        FILE *mp3 = fopen("file.mp3", "wb");
    
        const int MP3_SIZE = 8192;
    
        unsigned char pcm_buffer_c;
        short pcm_buffer;
        unsigned char mp3_buffer[MP3_SIZE];
    
        lame_t lame = lame_init();
        lame_set_num_samples(lame, 8000);
        lame_set_in_samplerate(lame, 8000);
        lame_set_out_samplerate(lame, 8000);
        lame_set_num_channels(lame, 1);
        lame_set_mode(lame, 3);
        lame_init_params(lame);
        lame_print_config(lame);
        //framesize is bits / channels = 8.
        do {
            read = fread(&pcm_buffer_c, sizeof(char), 1, pcm);
            pcm_buffer = (short)(pcm_buffer_c - 0x80) << 8;
            if (read == 0) {
                write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
                fwrite(mp3_buffer, sizeof(char), write, mp3);
                break;
            }
            write = lame_encode_buffer(lame, &pcm_buffer, NULL, read, mp3_buffer, MP3_SIZE);
            fwrite(mp3_buffer, sizeof(char), write, mp3);
        } while (1);
    
        lame_close(lame);
        fclose(mp3);
        fclose(pcm);
    
        return 0;
    }
    

    以上代码从输入文件一次读取1个字节,这不是非常有效。以下是您一次读取多个字节的方法(我还清理了一些代码并删除了一些不必要的函数)。此代码中没有错误检查,因此请确保添加对所有LAME库函数的返回值的检查。

    #include <stdio.h>
    #include <lame/lame.h>
    
    #define PCM_BUF_SIZE 1024
    #define MP3_SIZE 8192
    
    int main(int argc, char *argv[])
    {
        FILE *pcm = fopen(argv[1], "rb");
        FILE *mp3 = fopen("file.mp3", "wb");
    
        int n_bytes_read;
        int n_bytes_write;
        int i;
    
        short pcm_buffer_s[PCM_BUF_SIZE];
        unsigned char pcm_buffer[PCM_BUF_SIZE];
        unsigned char mp3_buffer[MP3_SIZE];
    
        lame_t lame = lame_init();
        lame_set_in_samplerate(lame, 8000);
        lame_set_num_channels(lame, 1);
        lame_set_mode(lame, 3);
        lame_init_params(lame);
        lame_print_config(lame);
        do {
            n_bytes_read = fread(pcm_buffer, sizeof(char), PCM_BUF_SIZE, pcm);
            for (i = 0; i < n_bytes_read; i++) {
                pcm_buffer_s[i] = (short)(pcm_buffer[i] - 0x80) << 8;
            }
            if (n_bytes_read == 0) {
                n_bytes_write = lame_encode_flush(lame, mp3_buffer, MP3_SIZE);
            } else {
                n_bytes_write = lame_encode_buffer(lame, pcm_buffer_s, NULL,
                        n_bytes_read, mp3_buffer, MP3_SIZE);
            }
            fwrite(mp3_buffer, sizeof(char), n_bytes_write, mp3);
        } while (n_bytes_read > 0);
    
        lame_close(lame);
        fclose(mp3);
        fclose(pcm);
    
        return 0;
    }