语音分帧简述

这篇具有很好参考价值的文章主要介绍了语音分帧简述。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

1. 分帧

1.1 非整齐分帧

1.2 整齐分帧

2. 示例代码


1. 分帧

问题1:总帧数如何计算?

记符号N为语音总长度,FRAME_LEN为帧长,OVERLAP_LEN为帧与帧之间的重叠部分,STEP_LEN为帧移(步长)。则总帧数N_Frames计算如下:

语音分帧简述,语音信号处理,语音分帧,算法,C语言

因为OVERLAP_LEN=FRAME_LEN-STEP_LEN

所以有:

语音分帧简述,语音信号处理,语音分帧,算法,C语言

N-FRAME_LEN可以看成一个常数。因此帧移越大,重叠部分就越小,总帧数就越小,反之;当帧移最大等于帧长的时候,式子变为:

语音分帧简述,语音信号处理,语音分帧,算法,C语言

此时就变成了均分了,而不是重叠分割了。

重叠分割的情况下,帧移的选择也影响整段语音分帧的结果,而实时语音处理中一般取N为256的整数倍。

问题2:关于输入和输出

重叠输入,按STEP_LEN输出。

1.1 非整齐分帧

非整齐分帧的情况下,有数据丢失。首先是输入,取帧数据的时候没法取到,其次是考虑到输出。例:N=2048,FRAME_LEN=256,当STEP_LEN=28+8=36时。总帧数N_Frames=(1792/36)+1=50,最后一帧的起始位置:49x36=1764,取最后一帧256个点,结果是1764+256=2020,即最后2048-2020=28个点没法取到。

语音分帧简述,语音信号处理,语音分帧,算法,C语言

 

1.2 整齐分帧

例:N=2048,FRAME_LEN=256,当STEP_LEN=128时,可以分为15帧(帧索引是0~14),刚好能把所有的点都取到,最后一个帧的起始位置:14x128=1792,再取一帧长256,刚好就是2048。由此类推,以下帧移,都能整齐分帧:

14x128=1792

28x64=1792

56x32=1792

112x16=1792

224x8=1792

第一列就是N_Frame,第二列就是帧移STEP_LEN。帧移越小,分的帧越多,计算量也就越大。一般取50%的重叠,即帧移和帧重叠各占50%。

语音分帧简述,语音信号处理,语音分帧,算法,C语言

 注:最后一帧全部输出即可。

2. 示例代码

#if 1
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "baselib.h"
#include "win_fun.h"

typedef unsigned char	uint8_t;

#define FRAME_LEN (256)
#define STEP_LEN (128)
//#define STEP_LEN (64)
//#define STEP_LEN (32)
//#define STEP_LEN (16)
//#define STEP_LEN (8)
#define OVERLAP_LEN (FRAME_LEN-STEP_LEN)

#define BLK_INPUT_LEN (4096)
//#define BLK_INPUT_LEN (8192)

static const float win[FRAME_LEN]={
	0.080000, 0.080140, 0.080558, 0.081256, 0.082232, 0.083487, 0.085018, 0.086825, 0.088908, 0.091264, 0.093893, 0.096793, 0.099962, 0.103398, 0.107099, 0.111063, 0.115287, 0.119769, 0.124506, 0.129496, 0.134734, 0.140219, 0.145946, 0.151913, 0.158115, 0.164549, 0.171211, 0.178097, 0.185203, 0.192524, 0.200056, 0.207794,
	0.215734, 0.223871, 0.232200, 0.240716, 0.249413, 0.258287, 0.267332, 0.276542, 0.285912, 0.295437, 0.305110, 0.314925, 0.324878, 0.334960, 0.345168, 0.355493, 0.365931, 0.376474, 0.387117, 0.397852, 0.408674, 0.419575, 0.430550, 0.441591, 0.452691, 0.463845, 0.475045, 0.486285, 0.497557, 0.508854, 0.520171, 0.531500,
	0.542834, 0.554166, 0.565489, 0.576797, 0.588083, 0.599340, 0.610560, 0.621738, 0.632866, 0.643938, 0.654946, 0.665885, 0.676747, 0.687527, 0.698216, 0.708810, 0.719301, 0.729684, 0.739951, 0.750097, 0.760115, 0.770000, 0.779745, 0.789345, 0.798793, 0.808084, 0.817212, 0.826172, 0.834958, 0.843565, 0.851988, 0.860222,
	0.868261, 0.876100, 0.883736, 0.891163, 0.898377, 0.905373, 0.912148, 0.918696, 0.925015, 0.931100, 0.936947, 0.942554, 0.947916, 0.953030, 0.957894, 0.962504, 0.966857, 0.970952, 0.974785, 0.978353, 0.981656, 0.984690, 0.987455, 0.989948, 0.992168, 0.994113, 0.995782, 0.997175, 0.998290, 0.999128, 0.999686, 0.999965,
	0.999965, 0.999686, 0.999128, 0.998290, 0.997175, 0.995782, 0.994113, 0.992168, 0.989948, 0.987455, 0.984690, 0.981656, 0.978353, 0.974785, 0.970952, 0.966857, 0.962504, 0.957894, 0.953030, 0.947916, 0.942554, 0.936947, 0.931100, 0.925015, 0.918696, 0.912148, 0.905373, 0.898377, 0.891163, 0.883736, 0.876100, 0.868261,
	0.860222, 0.851988, 0.843565, 0.834958, 0.826172, 0.817212, 0.808084, 0.798793, 0.789345, 0.779745, 0.770000, 0.760115, 0.750097, 0.739951, 0.729684, 0.719302, 0.708810, 0.698216, 0.687527, 0.676747, 0.665885, 0.654946, 0.643938, 0.632866, 0.621738, 0.610560, 0.599340, 0.588083, 0.576797, 0.565489, 0.554166, 0.542833,
	0.531500, 0.520171, 0.508854, 0.497557, 0.486285, 0.475045, 0.463845, 0.452692, 0.441591, 0.430550, 0.419575, 0.408674, 0.397852, 0.387117, 0.376474, 0.365931, 0.355493, 0.345168, 0.334960, 0.324877, 0.314925, 0.305110, 0.295437, 0.285912, 0.276542, 0.267331, 0.258287, 0.249413, 0.240716, 0.232200, 0.223871, 0.215734,
	0.207794, 0.200056, 0.192524, 0.185203, 0.178097, 0.171211, 0.164549, 0.158115, 0.151913, 0.145947, 0.140219, 0.134734, 0.129496, 0.124506, 0.119769, 0.115287, 0.111063, 0.107099, 0.103398, 0.099962, 0.096793, 0.093893, 0.091265, 0.088908, 0.086825, 0.085018, 0.083487, 0.082232, 0.081256, 0.080558, 0.080140, 0.080000,
};

//float winGain;
//int zero_cnt;
//int zero_idx;
void voice_frame(short *x, int Nframes, short *xout, int blk_index);

int main(void)
{
	int i, j;
	int inputdata_length;
	struct timeval start, end;
	int timeuse;
	FILE* input_ptr = NULL;
	FILE* output_ptr = NULL;

	input_ptr = fopen("80k.pcm", "r");
	if (!input_ptr) {
		printf("open input stream fail\n");
		return -1;
	}

	fseek(input_ptr, 0, SEEK_END);
	inputdata_length = ftell(input_ptr);
	printf("inputdata_length:%d\n", inputdata_length);
	rewind(input_ptr);

	uint8_t* all_in_dat = (uint8_t*)calloc(inputdata_length, sizeof(uint8_t));
	uint8_t* all_out_dat = (uint8_t*)calloc(inputdata_length, sizeof(uint8_t));

	uint8_t* blk_input_dat = (uint8_t*)calloc(BLK_INPUT_LEN, sizeof(uint8_t));
	uint8_t* blk_output_dat = (uint8_t*)calloc(BLK_INPUT_LEN, sizeof(uint8_t));

	int count = fread(all_in_dat, sizeof(uint8_t), inputdata_length, input_ptr);
	printf("count:%d\n", count);
	rewind(input_ptr);

	int in_dat_len=BLK_INPUT_LEN/2;
	int out_dat_len=in_dat_len;
	printf("in_dat_len:%d\n", in_dat_len);
	short* in_dat = (short*)calloc(in_dat_len, sizeof(short));
	short* out_dat = (short*)calloc(out_dat_len, sizeof(short));

	int all_block=inputdata_length/BLK_INPUT_LEN;
	printf("all_block:%d\n", all_block);

	//int Nframes= in_dat_len/OVERLAP_LEN-1;
	int Nframes= (in_dat_len-FRAME_LEN)/STEP_LEN+1;
	printf("a block can div to Nframes:%d\n", Nframes);

//	for(i=0; i<FRAME_LEN; i++){
//		winGain+=win[i];
//	}
//	winGain=STEP_LEN/winGain;	//normalization gain for overlap+add with 50% overlap
//	printf("winGain:%f\n", winGain);

	int block_index, arr_index;

	for (block_index=0; block_index<all_block; block_index++) {
		//分块
		for (arr_index=0; arr_index<BLK_INPUT_LEN; arr_index++) {

			blk_input_dat[arr_index]=all_in_dat[block_index*(BLK_INPUT_LEN)+arr_index];
		}

		//init input
		for(i=0, j=0; i<in_dat_len; i++) {
			in_dat[i]=(blk_input_dat[j+1]<<8|blk_input_dat[j]);
			j=j+2;
		}
#if 0
		voice_frame(in_dat, Nframes, out_dat, block_index);
#else
		gettimeofday(&start, NULL);
		voice_frame(in_dat, Nframes, out_dat, block_index);
		gettimeofday(&end, NULL);
		timeuse = 1000000 * ( end.tv_sec - start.tv_sec ) + end.tv_usec - start.tv_usec;
		printf("time=%.10fs\n", (double)timeuse/1000000);
#endif

#if 0
		/*非整齐分帧,帧尾只能舍去(相当于丢失了信息)*/
		/*非整齐分帧, 比如:STEP_LEN=40 */
		memset(out_dat, 0, out_dat_len);
		zero_cnt=0;
		voice_frame(in_dat, Nframes, out_dat, block_index);
		for(i=0, j=0; i<out_dat_len; i++) {
			//printf("%d:%d\n", i, out_dat[i]);
			if(out_dat[i]==0) {
				if(zero_cnt>5)
					zero_cnt++;
				else {
					if(out_dat[i+1]==0 && out_dat[i+2]==0) {
						zero_cnt++;
					}
				}
			}
		}

		if(zero_cnt!=0)
			printf("zero_idx:%d, zero_cnt:%d\n",out_dat_len-zero_cnt, zero_cnt);
#endif

#if 0
		for(i=0; i<in_dat_len; i++)
			out_dat[i]=in_dat[i];
#endif

		for(i=0, j=0; i<out_dat_len; i++) {
			blk_output_dat[j]=out_dat[i]&0xff; //low 8bit
			blk_output_dat[j+1]=((out_dat[i]>>8)&0xff); //high 8bit
			j=j+2;
		}

		//整合
		for (arr_index=0; arr_index<BLK_INPUT_LEN; arr_index++) {
			all_out_dat[block_index*BLK_INPUT_LEN+arr_index]=blk_output_dat[arr_index];
		}
	}

	output_ptr = fopen("output80k.pcm", "wb");
	if (!output_ptr) {
		printf("open output stream fail\n");
		return -1;
	}

	fwrite(all_out_dat, sizeof(uint8_t), inputdata_length, output_ptr);

	free(all_in_dat);
	free(all_out_dat);
	free(in_dat);
	free(out_dat);
	free(blk_input_dat);
	free(blk_output_dat);
	fclose(input_ptr);
	fclose(output_ptr);

	return 0;
}

float one_in_dat[FRAME_LEN];
float one_in_dat_i[FRAME_LEN];
float res_dat[FRAME_LEN];
float one_out_dat[STEP_LEN];

void voice_frame(short *x, int Nframes, short *xout, int blk_index)
{
	int i, /*j,*/ k, n;

//	printf("blk_index:%d, Nframes:%d\n\n", blk_index, Nframes);

	if(blk_index==0)
	{
		//printf("the first block, do somthing init\n");
		//
	}

	//=========================    Start Processing   ===============================
	for(n=0, k=0; n<Nframes; n++) {
		/*input*/
		for(i=0; i<FRAME_LEN; i++) {
			one_in_dat[i]=(x[k+i]/32768.0)*win[i];
			//one_in_dat[i]=(x[k+i]/32768.0);
			//one_in_dat[i]=x[k+i];
		}

		/*process*/
		memset(one_in_dat_i, 0, FRAME_LEN);
		baselib_fft(one_in_dat, one_in_dat_i, 1, FRAME_LEN);
		baselib_fft(one_in_dat, one_in_dat_i, -1, FRAME_LEN);
		for(i=0; i<FRAME_LEN; i++)
			res_dat[i]=one_in_dat[i]/win[i];

		/*output*/
		if(n==Nframes-1) {
			for(i=0; i<FRAME_LEN; i++){
				xout[k+i]=(short)(res_dat[i]*32768.0);
				//xout[k+i]=res_dat[i];
			}
			return;
		}

		for(i=0; i<STEP_LEN; i++){
			one_out_dat[i]=res_dat[i];
		}

		for(i=0; i<STEP_LEN; i++){
			xout[k+i]=(short)(one_out_dat[i]*32768.0);
			//xout[k+i]=one_out_dat[i];
		}

		//update step
		k=k+STEP_LEN;
	}

}
#else
/*Linux平台下,计算一段代码的运行时长*/
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include "cmath.h"

int int_cal()
{
    int i,j;
    int v;
    for (i = 0; i < 5000; i++) {
        for (j = 0; j < 500; j++) {
            v = Pow(i + j,  i + j);
            //v = 1.1 + i + j+2.2 + i + j;
        }
    }

	return v;
}

int main()
{
    struct timeval start, end;
    int timeuse;

    gettimeofday(&start, NULL);
    sleep(2);
    gettimeofday(&end, NULL);
    timeuse = 1000000 * ( end.tv_sec - start.tv_sec ) + end.tv_usec - start.tv_usec;
    printf("time=%.3fs\n", (double)timeuse/1000000);

    gettimeofday(&start, NULL);
    int_cal();
    gettimeofday(&end, NULL);
    timeuse = 1000000 * ( end.tv_sec - start.tv_sec ) + end.tv_usec - start.tv_usec;
    printf("time=%.3fs\n", (double)timeuse/1000000);
}
#endif

注:代码中有数据归一化,加窗,然后是FFT/IFFT。输入是一个长为80k的音频,分段输入算法再输出(2k输入,2k输出)。

X86平台上运行的结果:

inputdata_length:81920

count:81920

in_dat_len:2048

all_block:20

a block can div to Nframes:15

time=0.0002560000s

time=0.0002500000s

time=0.0002510000s

time=0.0002500000s

time=0.0002500000s

time=0.0002500000s

time=0.0002490000s

time=0.0002670000s

time=0.0002500000s

time=0.0002500000s

time=0.0002500000s

time=0.0002500000s

time=0.0002500000s

time=0.0002500000s

time=0.0002500000s

time=0.0002500000s

time=0.0002500000s

time=0.0002500000s

time=0.0002500000s

time=0.0002500000s

大概就是0.3ms结束运行。

输入输出音频对比:

语音分帧简述,语音信号处理,语音分帧,算法,C语言

语音分帧简述,语音信号处理,语音分帧,算法,C语言 如果不进行归一化,运行时间会减少很多。代码修改:

void voice_frame(short *x, int Nframes, short *xout, int blk_index)
{
	int i, /*j,*/ k, n;

//	printf("blk_index:%d, Nframes:%d\n\n", blk_index, Nframes);

	if(blk_index==0)
	{
		//printf("the first block, do somthing init\n");
		//
	}

	//=========================    Start Processing   ===============================
	for(n=0, k=0; n<Nframes; n++) {
		/*input*/
		for(i=0; i<FRAME_LEN; i++) {
			one_in_dat[i]=x[k+i]*win[i];
			//one_in_dat[i]=(x[k+i]/32768.0)*win[i];
			//one_in_dat[i]=(x[k+i]/32768.0);
			//one_in_dat[i]=x[k+i];
		}

		/*process*/
		memset(one_in_dat_i, 0, FRAME_LEN);
		baselib_fft(one_in_dat, one_in_dat_i, 1, FRAME_LEN);
		baselib_fft(one_in_dat, one_in_dat_i, -1, FRAME_LEN);
		for(i=0; i<FRAME_LEN; i++)
			res_dat[i]=one_in_dat[i]/win[i];

		/*output*/
		if(n==Nframes-1) {
			for(i=0; i<FRAME_LEN; i++){
				xout[k+i]=(short)res_dat[i];
				//xout[k+i]=(short)(res_dat[i]*32768.0);
				//xout[k+i]=res_dat[i];
			}
			return;
		}

		for(i=0; i<STEP_LEN; i++){
			one_out_dat[i]=res_dat[i];
		}

		for(i=0; i<STEP_LEN; i++){
			xout[k+i]=(short)res_dat[i];
			//xout[k+i]=(short)(one_out_dat[i]*32768.0);
			//xout[k+i]=one_out_dat[i];
		}

		//update step
		k=k+STEP_LEN;
	}

}

运行结果:

inputdata_length:81920

count:81920

in_dat_len:2048

all_block:20

a block can div to Nframes:15

time=0.0002430000s

time=0.0002390000s

time=0.0002380000s

time=0.0002380000s

time=0.0002380000s

time=0.0002380000s

time=0.0002660000s

time=0.0002620000s

time=0.0002380000s

time=0.0002380000s

time=0.0002380000s

time=0.0002380000s

time=0.0002380000s

time=0.0002380000s

time=0.0002390000s

time=0.0002380000s

time=0.0002570000s

time=0.0002390000s

time=0.0002380000s

time=0.0002380000s

大概就是0.2ms结束运行。有了统计运行时间的手段,就可以对算法进行时间上以及空间上的优化。文章来源地址https://www.toymoban.com/news/detail-606237.html

到了这里,关于语音分帧简述的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【数字信号处理课程设计】基于MATLAB实现语音信号的采集与处理(偏重滤波)

    目录 一、目标与任务 二、原理介绍 2.1 录音原理 2.2 滤波器的设计原理及设计方法 2.3 IIR 数字滤波器设计原理 2.4 双线性变换法 三、GUI界面设计与实现 四、基于MATLAB仿真 4.1实验过程 4.2 结果分析 五、总结 5.1 函数用法总结 5.2 心得体会 六、参考文献 这个项目在我的B站上有专

    2024年01月18日
    浏览(53)
  • 基于matlab的语音信号处理

    摘要 利用所学习的数字信号处理知识,设计了一个有趣的音效处理系统,首先设计了几种不同的滤波器对声音进行滤波处理,分析了时域和频域的变化,比较了经过滤波处理后的声音与原来的声音有何变化。同时设计实现了语音的倒放,变速播放,回响,音调转换等处理效果

    2024年02月08日
    浏览(45)
  • 语音识别入门第二节:语音信号处理及特征提取

    目录 数字信号处理基础 基础知识 傅里叶分析 常用特征提取 特征提取流程 Fbank MFCC 模拟信号到数字信号转化(ADC) :在科学和工程中,遇到的大多数信号都是连续的模拟信号,而计算机只能处理离散的信号,因此,必须对这些连续的模拟信号进行转化,通过采样和量化,转

    2024年02月10日
    浏览(42)
  • 利用matlab时频域语音信号的分析与处理

    鱼弦:CSDN内容合伙人、CSDN新星导师、51CTO(Top红人+专家博主) 、github开源爱好者(go-zero源码二次开发、游戏后端架构 https://github.com/Peakchen) 利用Matlab进行时频域语音信号的分析与处理:原理详解 时频域分析是对信号在时间和频率两个维度上进行分析的方法。在语音信号处理

    2024年02月06日
    浏览(42)
  • 毕业设计-基于MATLAB的含噪语音信号降噪处理系统

    目录 前言 课题背景和意义 实现技术思路 一、设计思路 二、IIR 数字滤波器的设计原理 三、语音信号的采集、 含噪语音信号的分析处理 四、总结 实现效果图样例 最后     📅大四是整个大学期间最忙碌的时光,一边要忙着备考或实习为毕业后面临的就业升学做准备,一边

    2024年02月07日
    浏览(128)
  • 语音信号处理基础知识之频谱、相位谱、幅度谱、功率谱及语谱图

    一段音频信号在时域上,可以用一个实数向量来表示。这个数组的大小=采样率*音频时长。举个例子:一段采样率为8000,长15.6s的音频在matlab中表示为: 15.6x8000=124800大小的实数向量 下面是利用matlab读取.wav文件和.pcm文件的两种方法 从上图可以看出,音频信号在matlab中就是用一

    2024年02月05日
    浏览(96)
  • 现代信号处理——阵列信号处理(空域滤波原理及其算法)

    一、阵列信号处理简介 1、阵列信号处理的研究内容:检测、估计、滤波、成像等。 2、阵列信号处理的研究对象:空间传播波携带信号(空域滤波) 3、阵列信号处理方法:统计与自适应信号处理技术(如谱估计、最优与自适应、滤波) 4、阵列信号处理的目的:①滤波:增强

    2024年02月02日
    浏览(91)
  • 语音处理加窗分帧

    语音数据和视频数据不同,本没有帧的概念,但是为了传输与存储,我们采集的音频数据都是一段一段 的。为了程序能够进行批量处理,会根据指定的长度(时间段或者采样数)进行分段,结构化为我们编程 的数据结构,这就是分帧。 由于我们常用的信号处理方法都要求信

    2024年02月01日
    浏览(21)
  • 聊聊音频信号处理中一个不太起眼的算法-limiter

    本文对笔者关于音频信号处理中的 Limiter 的理解作以记录。如有表述不当之处欢迎批评指正。欢迎任何形式的转载,但请务必注明出处。 由于工作上的需要,笔者花了一周左右的时间对 limiter (它属于动态范围控制器里面的一种算法,动态范围控制器包括 compressor, expander,

    2024年02月21日
    浏览(60)
  • 现代信号处理实验:MATLAB实现LD算法进行AR估计

    利用给定的一组样本数据估计一个平稳随机信号的功率谱密度称为功率谱估计,又称谱估计。谱估计的方法可以分成经典谱估计和现代谱估计。 经典谱估计又称为非参数化的谱估计,分为直接法和间接法。直接法是指直接计算样本数据的傅里叶变换,即获取频谱,然后计算频

    2024年02月03日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包