音频 -读写一个wave文件

折腾这么久,终于可以正常从硬盘读取wave文件了

上代码

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

#include <iostream>
#include<fstream>
#include<iomanip>

#include   <string.h>  
using namespace std;

struct WAV_Chunk_RIFF
{
	char ChunkID[4];    //理论上内容应该是:'RIFF' (0x52494646)
	uint32_t ChunkSize;  // 36 + Subchunk2Size Size是整个文件的长度减去ID和Size的长度
	char Format[4];     //理论上内容应该是:'WAVE'(0x57415645)
	WAV_Chunk_RIFF()//结构体也可以有构造函数,在里面可以对成员变量 赋值
	{
		strcpy(ChunkID, "RIFF");
		ChunkSize = 0;
		strcpy(Format, "W1VE");
	}
};

struct WAV_Chunk_FMT
{
	char ChunkID[4];    //理论上内容应该是:'fmt ' (0x666D7420)
	uint32_t ChunkSize; /*  Size表示该区块数据的长度(不包含ID和Size的长度) 16表示没有附加信息块*/
	uint16_t AudioFormat;   /* PCM = 1 	音频格式*/
	uint16_t NumChannels;   /* Mono = 1, Stereo = 2, etc. */
	uint32_t SampleRate;    /* 8000, 44100, etc. */
	uint32_t ByteRate;      /* = SampleRate * NumChannels * BitsPerSample/8 每秒数据字节数  */
	uint16_t BlockAlign;    /* = NumChannels * BitsPerSample/8 数据块对齐 */
	uint16_t BitsPerSample; /* 8bits, 16bits, etc.  采样位数 */
	WAV_Chunk_FMT()
	{
		strcpy(ChunkID, "fmt");
		ChunkSize = 16;
		AudioFormat = 1;
		NumChannels = 2;
		SampleRate = 44100;
		ByteRate = 0;
		BlockAlign = 0;
		BitsPerSample = 0;
	}
};

struct WAV_Chunk_data
{
	char ChunkID[4];    /* "data" */
	uint32_t ChunkSize; /* data size */
	char* Chunkdata;
	WAV_Chunk_data()
	{
		strcpy(ChunkID, "data");
		ChunkSize = 0;
		Chunkdata = (char*)"1234";
	}
};

struct WAV_fotmat
{
	WAV_Chunk_RIFF riff;
	WAV_Chunk_FMT fmt;
	WAV_Chunk_data data;
};



//声明一个函数:将wave文件从硬盘读取,并拆解
string   read_wave_file();
//声明一个函数:将数据以WAVE格式写入硬盘
string   write_wave_file();
 //一个全局的变量,用于表示一个WAV文件在内存中的样子
WAV_fotmat g_WAV_File;
int main()
{
	string gsz_rerurn =read_wave_file();
	std::cout<<"函数:read_wave_file的返回值----" << gsz_rerurn << "\n" << std::endl;
	gsz_rerurn = write_wave_file();
    std::cout << "Hello World!\n";
}
 
//将wave文件从硬盘读取,并拆解
string   read_wave_file()
{
	//第零步:从硬盘读取文件
	FILE* fp;
	fp = fopen("e:\\test3.wav", "rb");
	if (!fp)
	{
		return "error_fopen";
	}
	else
	{
		std::cout << "成功从硬盘找到并打开 wav文件\n";
	}


	//第一步:对RIFF区块的读取
	fread(g_WAV_File.riff.ChunkID, sizeof(char), 4, fp); // 读取'RIFF'
	if (('R' != g_WAV_File.riff.ChunkID[0]) || ('I' != g_WAV_File.riff.ChunkID[1]) || ('F' != g_WAV_File.riff.ChunkID[2]) || ('F' != g_WAV_File.riff.ChunkID[3]))//零	这两个字符串相等。
	{
		return  "error_RIFF_id";
	}
	//
	fread(&g_WAV_File.riff.ChunkSize, sizeof(unsigned long), 1, fp); // 读取文件大小(整个文件的长度减去ID和Size的长度)
	//
	fread(g_WAV_File.riff.Format, sizeof(char), 4, fp); // 读取'RIFF'
	if (('W'!=g_WAV_File.riff.Format[0])||('A' != g_WAV_File.riff.Format[1]) || ('V' != g_WAV_File.riff.Format[2]) || ('E' != g_WAV_File.riff.Format[3]))
	{
		return "error_WAVE";
	}

	//第二步:FORMAT区块
	fread(g_WAV_File.fmt.ChunkID, sizeof(char), 4, fp);     // 读取4字节 "fmt ";
	 
	fread(&g_WAV_File.fmt.ChunkSize, sizeof(unsigned long), 1, fp);//Size表示该区块数据的长度(不包含ID和Size的长度)
	//若Format Chunk的size大小为18,则该模块的最后两个字节为附加信息
	std::cout << "函数:read_wave_file--format_length----" << g_WAV_File.fmt.ChunkSize << "\n" << std::endl;
	if (18 == g_WAV_File.fmt.ChunkSize)
	{
		std::cout << "函数:read_wave_file--该WAVE文件里面有附加信息块----" << "\n" << std::endl;
		std::cout << "本程序,不支持 对附加信息读取!!!" << "\n" << std::endl;
	}
	else
	{
		std::cout << "函数:read_wave_file--该WAVE文件里面没有附加信息块----" << "\n" << std::endl;
	}
	fread(&g_WAV_File.fmt.AudioFormat, sizeof(short), 1, fp); // 读取文件tag  音频格式 PCM信号采样 = 1
	std::cout << "函数:read_wave_file--音频格式----" << g_WAV_File.fmt.AudioFormat << "\n" << std::endl;

	fread(&g_WAV_File.fmt.NumChannels, sizeof(short), 1, fp);    // 读取通道数目
	std::cout << "函数:read_wave_file--通道数目----" << g_WAV_File.fmt.NumChannels << "\n" << std::endl;

	fread(&g_WAV_File.fmt.SampleRate, sizeof(unsigned long), 1, fp);   // 读取采样率大小 
	std::cout << "函数:read_wave_file--采样率大小----" << g_WAV_File.fmt.SampleRate << "\n" << std::endl;

	fread(&g_WAV_File.fmt.ByteRate, sizeof(unsigned long), 1, fp);//每秒数据字节数 SampleRate * NumChannels * BitsPerSample / 8
	std::cout << "函数:read_wave_file--每秒数据字节数----" << g_WAV_File.fmt.ByteRate << "\n" << std::endl;

	fread(&g_WAV_File.fmt.BlockAlign, sizeof(short), 1, fp);     //每个采样所需的字节数 = NumChannels * BitsPerSample / 8
	std::cout << "函数:read_wave_file--每个采样所需的字节数----" << g_WAV_File.fmt.BlockAlign << "\n" << std::endl;

	fread(&g_WAV_File.fmt.BitsPerSample, sizeof(short), 1, fp);      // 每个采样存储的bit数,8:8bit,16:16bit,32:32bit
	std::cout << "函数:read_wave_file--每个采样存储的bit数----" << g_WAV_File.fmt.BitsPerSample << "\n" << std::endl;

	//第三步: DATA区块
	fread(g_WAV_File.data.ChunkID, sizeof(char), 4, fp);                     // 读入'data'
	if (('d' != g_WAV_File.data.ChunkID[0]) || ('a' != g_WAV_File.data.ChunkID[1]) || ('t' != g_WAV_File.data.ChunkID[2]) || ('a' != g_WAV_File.data.ChunkID[3]))
	{
		return "error_data";
	}
	//震动数据的字节数目
	fread(&g_WAV_File.data.ChunkSize, sizeof(unsigned long), 1, fp);    // 读取数据大小
	std::cout << "函数:read_wave_file--数据大小----" << g_WAV_File.data.ChunkSize << "\n" << std::endl;
	//震动数据本身
	g_WAV_File.data.Chunkdata = new char[g_WAV_File.data.ChunkSize];// 读取数据
	fread(g_WAV_File.data.Chunkdata, sizeof(char), g_WAV_File.data.ChunkSize, fp);
	 //for (int i = 0; i < 100; i++)
	 //{
		// uint16_t left=0;
		// fread(&left, sizeof(char),2, fp);
		// //数据的存储位置。
		// //项目大小(以字节为单位)。
		// //要读取的项的最大数量。
		// //指向 FILE 结构的指针。
		// std::cout << "16位--双字节数据--"<< dec << left << "\n" << std::endl;
	 //}
	
	//如果16位双通道,那么数据应该是L低字节,L高字节,R低字节,R高字节,

	return "read_wave_file_OK";
}

//将数据以WAVE格式写入硬盘
string   write_wave_file()
{
	ofstream fout("Wave__11.wav", ios::binary);

	int  a = sizeof(g_WAV_File.riff);
	fout.write((char*)(&g_WAV_File.riff), a);


	int  b = sizeof(g_WAV_File.fmt);
	fout.write((char*)(&g_WAV_File.fmt), b);

	int c= sizeof(g_WAV_File.data.ChunkID);
	fout.write((char*)(&g_WAV_File.data.ChunkID),c);

	int d = sizeof(g_WAV_File.data.ChunkSize);
	fout.write((char*)(&g_WAV_File.data.ChunkSize), d);


	fout.write((char*)(g_WAV_File.data.Chunkdata), g_WAV_File.data.ChunkSize);

	return "write_wave_file_OK";
}

***

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值