1. 语音类实现 (实现读取wav/pcm,STFT)

[C++ 基于Eigen库实现CRN前向推理]

第一部分:WavFile.class (实现读取wav/pcm,实现STFT)

1. 读写语音文件(wav/pcm)
1.1 wav文件读写

语音文件有很多后缀格式,这里只实现了两种后缀名,.wav和.pcm。

  • WAV文件遵守资源交换文件格式之规则,在文件的前44(或46)字节放置标头(header),使播放器或编辑器能够简单掌握文件的基本信息,其内容以区块(chunk)为最小单位,每一区块长度为4字节,而区块之上则由子区块包裹,每一子区块长度不拘,但须在前头先宣告标签及长度(字节)。
  • 标头的前3个区块记录文件格式及长度;
  • 接着第一个子区块包含8个区块,记录声道数量、采样率等信息;
  • 接着第二个子区块才是真正的音频资料,长度则视音频长度而定。
  • 内容如下表所示。须注意的是,每个区块的端序不尽相同,而音频内容本身则是采用小端序。

在这里插入图片描述

  • 读Wav文件
    图中所示是一个wav的标准格式,但wav还有其他不同的存储格式,有些有扩展块之类的,需要根据具体的语音文件来确定。比如我用python中soudfile生成的语音,其format_tag=3,format_length=18(通常为16)。由于我没用到其他格式的情况,直接在下方用if else讨论format_tag=1和=3的情况。
    总而言之,读取wav其实就是一个解析头文件的过程,把对应的头信息存下来,再去读取数据就好了。-
    读wav文件的具体代码给出(后面会给整体的h文件和cpp文件):

    void Wav_File::LoadWavFile(const char *file_path) {
         
        FILE *fp = fopen(file_path, "rb");
        if (fp) {
         
            fread(this->id_riff, sizeof(char), 4, fp);
            this->id_riff[4] = '\0';
            fread(&this->file_size, sizeof(int16_t), 2, fp);
            fread(this->id_wave, sizeof(char), 4, fp);
            this->id_wave[4] = '\0';
            fread(this->id_fmt, sizeof(char), 4, fp);
            this->id_fmt[4] = '\0';
            fread(&this->format_length, sizeof(int16_t), 2, fp);
            fread(&this->format_tag, sizeof(int16_t), 1, fp);
            fread(&this->channels, sizeof(int16_t), 1, fp);
            fread(&this->sample_rate, sizeof(int16_t), 2, fp);
            fread(&this->avg_bytes_sec, sizeof(int16_t), 2, fp);
            fread(&this->block_align, sizeof(int16_t), 1, fp);
            fread(&this->bits_per_sample, sizeof(int16_t), 1, fp);
            if (this->format_tag == 1) {
         
                fread(this->id_data, sizeof(char), 4, fp);
                this->id_data[4] = '\0';
                fread(&this->data_size, sizeof(int16_t), 2, fp);
                this->wav_size = this->data_size / sizeof(int16_t);
                this->ip_raw = (int16_t *) malloc(this->data_size);
                fread(this->ip_raw, sizeof(int16_t), this->wav_size, fp);
    
                this->data = (float_t *) malloc(this->wav_size * sizeof(float_t));
                for (int i = 0; i < this->wav_size; i++) {
         
                    this->data[i] = (float_t) (this->ip_raw[i] * 1.0 / 32768);
                }
    
            } else if (this->format_tag == 3) {
         
                fread(&this->cb_size, sizeof(int16_t), 1, fp);
                fread(this->id_data, sizeof(char), 4, fp);
                this->id_data[4] = '\0';
                fread(&this->data_size, sizeof(int16_t), 2, fp);
                this->wav_size = this->data_size / sizeof(float);
                this->fp_raw = (float *) malloc(this->data_size);
                fread(this->fp_raw, sizeof(float), this->wav_size, fp);
                this->data = (float_t *) malloc(this->wav_size * sizeof(float_t));
                for (int i = 0; i < this->wav_size; i++) {
         
                    this->data[i] = this->fp_raw[i];
                }
            }
        }
        fclose(fp);
    
    }
    
  • 写出Wav文件
    Wav文件写出和读入是完全对应的,把读到的信息反向写出就可以了。
    如果对数据有所操作,需要去找对应的变量进行修改,比如长度,需要更新总文件的file_size以及data chunk的data_size。
    具体代码给出:

    void Wav_File::WriteWavFile(const char *dest_path) {
         
        for (int i = 0; i < wav_size; i++) {
         
            if (format_tag == 1)
                this->ip_raw[i] = (int16_t) (this->data[i] * 32768);
            else
                this->fp_raw[i] = this->data[i];
        }
    
        FILE *fp = fopen(dest_path, "wb");
        if (fp) {
         
    
            fwrite(this->id_riff, sizeof(char), 4, fp);
            fwrite(&this->file_size, sizeof(int16_t), 2,
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值