音频-从零开始创建一个wave 文件,并且写入硬盘(版本2)

前面写了一个,今天更新一下

主要更新内容如下:

1)增加注释,简化程序

2)实现音频数据自身频率的变化。实现类似扫频的效果

***

// CreateWaveWriteDisk.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <cmath>
#include<cstdint>
#include<fstream>
#include<iomanip>

using namespace std;

uint32_t endianSwap(uint32_t n) //大小端转换
{
    uint32_t changed = 0;
    for (int i = 0; i < 4; i++)
    {
        changed <<= 8;
        changed |= (n << ((3 - i) * 8)) >> 24;
    }
    return changed;
}

struct RIFF
{
    char chunkID[4];
    uint32_t chunkSize;
    char format[4];
    RIFF(uint32_t n)//结构体里面竟然可以有构造函数, 这个构造函数竟然可以有参数。 晕,基本功不扎实啊。。
    {
        chunkID[0] = 'R';
        chunkID[1] = 'I';
        chunkID[2] = 'F';
        chunkID[3] = 'F';
        uint32_t ChunkSize = n + 36;//36 + Subchunk2Size Size是整个文件的长度减去ID和Size的长度
        chunkSize = ChunkSize;
        format[0] = 'W';
        format[1] = 'A';
        format[2] = 'V';
        format[3] = 'E';
    }
};

struct FMT
{
    char subchunk1ID[4];
    uint32_t subchunk1Size;//16
    uint16_t audioFormat;//1
    uint16_t numChannels;
    uint32_t sampleRate;
    uint32_t byteRate;//数据传送速率(每秒字节=采样频率×每个样本字节数
    uint16_t blockAlign;// = NumChannels * BitsPerSample / 8= 2*16/8=4
    uint16_t bitsPerSample;
    FMT(uint32_t NumChannels, uint32_t SampleRate, uint32_t BitsPerSample) :
        subchunk1Size(16), audioFormat(1), numChannels(NumChannels),
        sampleRate(SampleRate), blockAlign(4), bitsPerSample(BitsPerSample) //尼玛,好复杂的语法。就是为了给结构体的变量赋值
    {
        subchunk1ID[0] = 'f';
        subchunk1ID[1] = 'm';
        subchunk1ID[2] = 't';
        subchunk1ID[3] = ' ';
        byteRate = SampleRate * NumChannels * BitsPerSample >> 3;//44100*2*16=1,411,200
    }
};

//这个是data块里面 :ID和SIZE 两个参数的赋值
struct DATA_HEADER
{
    char subchunk2ID[4];
    uint32_t subchunk2Size;
    DATA_HEADER(uint32_t n) : subchunk2Size(n)
    {
        subchunk2ID[0] = 'd';
        subchunk2ID[1] = 'a';
        subchunk2ID[2] = 't';
        subchunk2ID[3] = 'a';
    }
};

struct DATA_BLOCK
{
    uint16_t left;
    uint16_t right;
    DATA_BLOCK(uint16_t Left, uint16_t Right) :
        left(Left), right(Right)
    {
    }
};

const double PI = acos(-1.0);

int main()
{
    int gsz_time_s= 10;//设定音频时间 ,单位是S。
    uint16_t gsz_numChannels=2;//设定通道数目为2
    uint32_t gsz_sampleRate=44100;//设定采样频率为44.1K。
    uint16_t gsz_bitsPerSample=16;//设定每通道每次采样得到的数据AD转化位数

    uint16_t gsz_blockAlign= (gsz_numChannels* gsz_bitsPerSample)/8;  // = NumChannels * BitsPerSample / 8= 2*16/8=4
    uint32_t gsz_byteRate= gsz_sampleRate* gsz_blockAlign;            //数据传送速率(每秒字节)=采样频率×每个样本字节数=176,400字节


    int gsz_size_Riff = 4 + 4 + 4;// RIFF区块的大小=ID+SIZE+Type=12
    int gsz_size_FORMAT = 4 + 4 + 2 + 2 + 4 + 4 + 2 + 2;// FORMAT区块=ID+SIZE+AudioFormat+NumChannels+SampleRate+ByteRate+BlockAlign+BitsPerSample=24

    int gsz_size_data_ID = 4;//DATA区块的ID是四个字节
    int gsz_size_data_szie = 4;DATA区块的SIZE也是四个字节Size表示音频数据的长度
    
    //所以整个WAVE文件的大小就是:12+24+8+176,400*10=1 764 044
    uint32_t gsz_total_wave_size = gsz_size_Riff+ gsz_size_FORMAT+ gsz_size_data_ID+ gsz_size_data_szie+ gsz_time_s* gsz_byteRate;
    printf("整个wave文件的大小是:%u\n", gsz_total_wave_size);

    ofstream fout("Wave.wav", ios::binary);
    RIFF riff(gsz_time_s * gsz_byteRate);//此处填写的整个测试时间内,震动数据的占用的字节数目
     
    
    FMT fmt(gsz_numChannels, gsz_sampleRate, gsz_bitsPerSample);//2个声道,信号采样率44.1K。 每个数据用16个b,两个字节存储。

     
    DATA_HEADER dataHeader(gsz_time_s * gsz_byteRate);
    fout.write((char*)(&riff), sizeof(riff));
    fout.write((char*)(&fmt), sizeof(fmt));
    fout.write((char*)(&dataHeader), sizeof(dataHeader));
    for (int i = 0; i < 44100* gsz_time_s; i++) //采样率是44100,此处循环了441000  是10倍的44.1K。那就是10S的音频数据了
    {
        int gsz_shang = i / 4410;
        printf("商等于:%d\n", gsz_shang);
        double Sin = sin(2 * PI * (200+gsz_shang*150) * i / 44100);//2*圆周率*频率*采样点
        int16_t Data = (int16_t)(Sin * 32767);//振幅 最大=位数的最大
        uint16_t* data = (uint16_t*)&Data;
        DATA_BLOCK block(*data, *data);
        fout.write((char*)(&block), sizeof(block));
    }//生成远程的震动数目 因为无符号16位
    
    
     
    fout.close();
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值