使用libspeex实现原始音频文件的编码和解码技术

送分小仙女□ 提交于 2021-01-05 10:23:54

这几天在单位研究使用libspeex对原始音频文件(PCM文件)进行编解码。在linux下原始音频文件可以通过arecord命令进行采集,使用的采样率是8kHz,量化位数为有符号16位整数(小端存储),单通道模式。在linux下播放原始音频文件可以通过使用aplay命令进行播放,在播放的时候需要给出量化位数参数,因为aplay默认使用8位无符号数进行量化取样。

下面分别是编码和解码的源代码,注意linux编译环境需要有speex(speex运行库包)和speex_devel(speex开发包)。

声音录制和编码源代码:

/*

 * =====================================================================================

 *

 *       Filename:  record_spx.c

 *

 *    Description:  

 *

 *        Version:  1.0

 *        Created:  12/01/2011 12:49:48 PM

 *       Revision:  none

 *       Compiler:  gcc

 *

 *         Author:  YOUR NAME (), 

 *        Company:  

 *

 * =====================================================================================

 */

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

#include <string.h>

#include <signal.h>

#include <sys/wait.h>

#include <sys/types.h>

#include <speex/speex.h>

 

#define DEFAULT_RATE 8000

#define DEFAULT_RECORD_DURING 60

#define DEFAULT_ALSA_REC_FILE "/tmp/xk_rec.wav"

#define FRAME_SIZE 160

#define RECORD_CMD_LENGTH 128

 

#define DEBUG_ON 1

 

#if DEBUG_ON

 

#define DEBUG_FILE "/tmp/xk_recorder.log"

 

#define DEBUG_TOOL(flag, fmt...) \

do { \

if (flag) { \

FILE *fp; \

fp = fopen(DEBUG_FILE, "a"); \

fprintf(fp, "%s[%d]", __FILE__, __LINE__); \

fprintf(fp, fmt); \

fclose(fp); \

} \

} \

while(0) 

#else

#define DEBUG_TOOL(flag, fmt...)

#endif

 

static int flag = 0;

 

void print_usage(void)

{

printf("usage: speex_recorder <speex file(.spx)>\n");

return;

}

 

int run_command(const char *cmd)

{

int retval;

 

retval = system(cmd);

if (retval == 127) {

DEBUG_TOOL(DEBUG_ON, "command not available\n");

} else if (retval == -1) {

DEBUG_TOOL(DEBUG_ON, "system() error.\n");

} else if (retval != 0) {

DEBUG_TOOL(DEBUG_ON, "command return %d\n", retval);

} else {

DEBUG_TOOL(DEBUG_ON, "system(\"%s\") successful.\n", cmd);

}

return retval;

}

 

int record_alsa(const char *wave_file)

{

char cmd[RECORD_CMD_LENGTH];

int child, status, wait_child;

 

memset(cmd, 0, sizeof(cmd));

snprintf(cmd, sizeof(cmd), "arecord -t raw -f S16_LE -c 1 -r %d -d %d %s 1>/dev/null 2>&1",DEFAULT_RATE, DEFAULT_RECORD_DURING, wave_file);

if ((child = fork()) < 0 ) {

DEBUG_TOOL(DEBUG_ON, "fork() error.\n");

return -1;

} else if (child == 0) {

run_command(cmd);

return 0;

} else {

while(1) {

if (flag) {

DEBUG_TOOL(DEBUG_ON, "pause arecord process\n");

system("killall arecord");

break;

}

usleep(1000);

wait_child = waitpid(child, &status, WNOHANG||WUNTRACED);

if (wait_child == child) {

DEBUG_TOOL(DEBUG_ON, "arecord completed\n");

break;

}

}

return 0;

}

}

 

int build_spx_from_wave(const char *wave_file, const char *spx_file)

{

#if 0

char cmd[RECORD_CMD_LENGTH];

int retval;

 

memset(cmd, 0, sizeof(cmd));

snprintf(cmd, sizeof(cmd), "speexenc --wideband --vbr --rate %d --le --16bit %s %s 1>/dev/null 2>&1", DEFAULT_RATE, wave_file, spx_file);

retval = run_command(cmd);

return retval;

#else

const char *inFile, *outFile;

FILE *fin, *fout;

short in[FRAME_SIZE];

short input[FRAME_SIZE];

char cbits[200];

int nbBytes;

/*Holds the state of the encoder*/

void *state;

/*Holds bits so they can be read and written to by the Speex routines*/

SpeexBits bits;

int i, tmp;

 

/*Create a new encoder state in narrowband mode*/

state = speex_encoder_init(&speex_nb_mode);

 

/*Set the quality to 8 (15 kbps)*/

tmp=8;

speex_encoder_ctl(state, SPEEX_SET_QUALITY, &tmp);

 

inFile = wave_file;

outFile = spx_file;

fin = fopen(inFile, "r");

fout = fopen(outFile, "w");

 

/*Initialization of the structure that holds the bits*/

speex_bits_init(&bits);

while (1)

{

/*Read a 16 bits/sample audio frame*/

fread(in, sizeof(short), FRAME_SIZE, fin);

if (feof(fin))

break;

/*Copy the 16 bits values to float so Speex can work on them*/

for (i=0;i<FRAME_SIZE;i++)

input[i]=in[i];

 

/*Flush all the bits in the struct so we can encode a new frame*/

speex_bits_reset(&bits);

 

/*Encode the frame*/

speex_encode_int(state, input, &bits);

/*Copy the bits to an array of char that can be written*/

nbBytes = speex_bits_write(&bits, cbits, 200);

 

/*Write the size of the frame first. This is what sampledec expects but

 it's likely to be different in your own application*/

fwrite(&nbBytes, sizeof(int), 1, fout);

/*Write the compressed data*/

fwrite(cbits, 1, nbBytes, fout);

 

}

 

/*Destroy the encoder state*/

speex_encoder_destroy(state);

/*Destroy the bit-packing struct*/

speex_bits_destroy(&bits);

fclose(fin);

fclose(fout);

return 0;

#endif

}

 

int record_spx(const char *spx_file)

{

int retval;

 

retval = record_alsa(DEFAULT_ALSA_REC_FILE);

if (retval == 127 || retval < 0) {

DEBUG_TOOL(DEBUG_ON, "record_alsa() error.\n");

return -1;

}

retval = build_spx_from_wave(DEFAULT_ALSA_REC_FILE, spx_file);

if (retval == 127 || retval < 0) {

DEBUG_TOOL(DEBUG_ON, "build_spx_from_wave() error.\n");

return -2;

}

unlink(DEFAULT_ALSA_REC_FILE);

return 0;

}

 

void pause_record(int signal)

{

flag = 1;

return;

}

 

int main(int argc, char **argv)

{

int retval;

const char *speex_file;

 

if (argc != 2) {

print_usage();

return -1;

}

speex_file = argv[1];

 

signal(SIGTERM, pause_record);

 

retval = record_spx(speex_file);

return retval;

}

声音播放和解码源代码:
/*
 * =====================================================================================
 *
 *       Filename:  record_spx.c
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  12/01/2011 12:49:48 PM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  YOUR NAME (), 
 *        Company:  
 *
 * =====================================================================================
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <speex/speex.h>

#define DEFAULT_RATE 8000
#define DEFAULT_ALSA_PLAY_FILE "/tmp/xk_play.wav"
#define FRAME_SIZE 160
#define RECORD_CMD_LENGTH 128

#define DEBUG_ON 1

#if DEBUG_ON

#define DEBUG_FILE "/tmp/xk_record.log"

#define DEBUG_TOOL(flag, fmt...) \
do { \
if (flag) { \
FILE *fp; \
fp = fopen(DEBUG_FILE, "a"); \
fprintf(fp, "%s[%d]", __FILE__, __LINE__); \
fprintf(fp, fmt); \
fclose(fp); \
} \
} \
while(0) 
#else
#define DEBUG_TOOL(flag, fmt...)
#endif

void print_usage(void)
{
printf("usage: speex_player <speex file(.spx)>\n");
return;
}

int run_command(const char *cmd)
{
int retval;

retval = system(cmd);
if (retval == 127) {
DEBUG_TOOL(DEBUG_ON, "command not available\n");
} else if (retval == -1) {
DEBUG_TOOL(DEBUG_ON, "system() error.\n");
} else if (retval != 0) {
DEBUG_TOOL(DEBUG_ON, "command return %d\n", retval);
} else {
DEBUG_TOOL(DEBUG_ON, "system(\"%s\") successful.\n", cmd);
}
return retval;
}

int play_alsa(const char *wave_file)
{
char cmd[RECORD_CMD_LENGTH];
memset(cmd, 0, sizeof(cmd));
snprintf(cmd, sizeof(cmd), "aplay -t raw -f S16_LE -c 1 -r 8000 %s 1>/dev/null 2>&1", wave_file);
return run_command(cmd);
}

int build_wave_from_spx(const char *spx_file, const char *wave_file)
{
#if 0
char cmd[RECORD_CMD_LENGTH];

memset(cmd, 0, sizeof(cmd));
snprintf(cmd, sizeof(cmd), "speexdec --force-wb --mono --rate %d %s %s 1>/dev/null 2>&1", DEFAULT_RATE, spx_file, wave_file);
return run_command(cmd);
#else
const char *outFile, *inFile;
FILE *fout, *fin;
/*Holds the audio that will be written to file (16 bits per sample)*/
short out[FRAME_SIZE];
/*Speex handle samples as float, so we need an array of floats*/
short output[FRAME_SIZE];
char cbits[200];
int nbBytes;
/*Holds the state of the decoder*/
void *state;
/*Holds bits so they can be read and written to by the Speex routines*/
SpeexBits bits;
int i, tmp;

/*Create a new decoder state in narrowband mode*/
state = speex_decoder_init(&speex_nb_mode);

/*Set the perceptual enhancement on*/
tmp=1;
speex_decoder_ctl(state, SPEEX_SET_ENH, &tmp);
inFile = spx_file;
outFile = wave_file;
fin = fopen(inFile, "r");
fout = fopen(outFile, "w");

/*Initialization of the structure that holds the bits*/
speex_bits_init(&bits);
while (1)
{
/*Read the size encoded by sampleenc, this part will likely be 
 different in your application*/
fread(&nbBytes, sizeof(int), 1, fin);
fprintf (stderr, "nbBytes: %d\n", nbBytes);
if (feof(fin))
break;

/*Read the "packet" encoded by sampleenc*/
fread(cbits, 1, nbBytes, fin);
/*Copy the data into the bit-stream struct*/
speex_bits_read_from(&bits, cbits, nbBytes);

/*Decode the data*/
speex_decode_int(state, &bits, output);

/*Copy from float to short (16 bits) for output*/
for (i=0;i<FRAME_SIZE;i++)
out[i]=output[i];

/*Write the decoded audio to file*/
fwrite(out, sizeof(short), FRAME_SIZE, fout);
}

/*Destroy the decoder state*/
speex_decoder_destroy(state);
/*Destroy the bit-stream truct*/
speex_bits_destroy(&bits);
fclose(fin);
fclose(fout);
return 0;
#endif
}

int play_spx(const char *spx_file)
{
int retval;

retval = build_wave_from_spx(spx_file, DEFAULT_ALSA_PLAY_FILE);
if (retval == 127 || retval < 0) {
DEBUG_TOOL(DEBUG_ON, "build_wave_from_spx() error.\n");
return -2;
}

retval = play_alsa(DEFAULT_ALSA_PLAY_FILE);
if (retval == 127 || retval < 0) {
DEBUG_TOOL(DEBUG_ON, "play_alsa() error.\n");
return -1;
}
unlink(DEFAULT_ALSA_PLAY_FILE);
return 0;
}

int main(int argc, char **argv)
{
int retval;
const char *speex_file;
if (argc != 2) {
print_usage();
return -1;
}
speex_file = argv[1];

retval = play_spx(speex_file);
return retval;
}


易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!