【CS50x】Volume 题解

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第8天,点击查看活动详情

前言

CS50x 是哈佛大学推出的一门知名公开课,本课程是一门计算机科学的导论课程,适合于对计算机科学感兴趣的任何人学习,不需要任何基础。通过学习本课程有助于对计算机科学的体系建立一个基本的概念,其学习内容如下:

image.png

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);
}
复制代码

猜你喜欢

转载自juejin.im/post/7106897758321770503