前言
CS50x 是哈佛大学推出的一门知名公开课,本课程是一门计算机科学的导论课程,适合于对计算机科学感兴趣的任何人学习,不需要任何基础。通过学习本课程有助于对计算机科学的体系建立一个基本的概念,其学习内容如下:
WAV
本题要求我们读取以 .wav 为后缀的音频文件,然后修改其音量。
要修改 WAV 文件的音量,首先我们需要了解 WAV 文件格式,WAV 文件是表示音频的通用文件格式。
WAV 文件以样本的形式存储音频,数字表示某个特定时间点某个音频信号的值。
从一个44字节的“头部”开始,其中包含文件本身的信息,包括文件的大小、每秒的样本数以及每个样本的大小。
在头部之后,WAV 文件包含一系列样本,每个样本都是一个2字节(16位)的整数,表示特定时间点的音频信号,我们可以将每个样本值乘以2.0,以得到原始音频音量加倍的效果,同理每个样本乘以0.5将会减少一半的音量。
所以这里我们将会用到 C 语言的两种类型:uint8_t
以及 int16_t
,分别读取头部和样本。你可以从命名中看出他们的作用,uint8 即 unsigned int 8,用来读取8位无符号整数(即非负数),int16 用来读取16位有符号整数。
Volume
要求使用命令行输入形如 ./volume INPUT.wav OUTPUT.wav 2.0
的命令来获得输入及输出后的文件,2.0即加倍原始音量。
首先我们需要通过 fopen()
来读写文件,通过不同参数 r 和 w 来达到效果,别忘了最后用 fclose()
关闭文件流,否则会造成内存泄漏
#include <stdint.h> #include <stdio.h> #include <stdlib.h> // 头部大小 const int HEADER_SIZE = 44; int main(int argc, char *argv[]) { // 检查命令行参数 if (argc != 4) { printf("Usage: ./volume input.wav output.wav factor\n"); return 1; } FILE *input = fopen(argv[1], "r"); if (input == NULL) { printf("Could not open file.\n"); return 1; } FILE *output = fopen(argv[2], "w"); if (output == NULL) { printf("Could not open file.\n"); return 1; } // TODO fclose(input); fclose(output); } 复制代码
获得需要的文件流后,我们就可以开始改造音量了。
通过 fread()
和 fwrite()
函数来进行读写,参数为(读写的文件流,每次读写的大小,读写次数,读写的文件流),仿照去写就ok了:
// TODO // 将因子从string转换成float类型 float factor = atof(argv[3]); // 将原本的头部复制到输出文件中 uint8_t header[HEADER_SIZE]; fread(header, HEADER_SIZE, 1, input); fwrite(header, HEADER_SIZE, 1, output); int16_t buffer; while (fread(&buffer, sizeof(int16_t), 1, input)) { // 将每个样本乘以因子后写入输出文件 buffer *= factor; fwrite(&buffer, sizeof(int16_t), 1, output); }