Lab4: ボリューム

この Lab では1~2人のクラスメートと協力することは問題ありませんが、そのグループのすべての受講生が等しく実習に貢献することが求められます。

オーディオファイルの音量を変更するプログラムを記述します。

$ ./volume input.wav output.wav 2.0

〆切

2021年12月31日金曜日11:59 PM (東部標準時) までに提出してください。

WAVファイル

WAVファイルは、オーディオを表すための一般的なファイル形式です。WAVファイルには、オーディオがシーケンスの「サンプル」 (特定の時点でのオーディオ信号の値を表す数字) として保存されます。WAVファイルは、ファイルのサイズ、毎秒のサンプル数、各サンプルのサイズなど、ファイル自体に関する情報を含む44バイトの 「ヘッダー」 で始まります。ヘッダーの後に、WAVファイルには一連のサンプルが含まれています。各サンプルは、特定の時点でのオーディオ信号を表す2バイト (16ビット) の整数です。

各サンプル値を指定の係数でスケールすると、オーディオのボリュームが変化します。たとえば、各サンプル値に2.0を掛けると、元のオーディオのボリュームが倍になります。各サンプルを0.5倍にすると、ボリュームは半分になります。

これまでのところ、intboolchardoublefloatlongなど、Cにはさまざまな型があることを見てきました。stdint.hと呼ばれるヘッダファイルの中には、整数のサイズ (ビット単位) と符号 (符号付きまたは符号なし) を非常に正確に定義することを可能にする多くの他の型の宣言があります。この実習では、特に2つのタイプが役立ちます。

  • uint8_tは8ビットの符号なし (すなわち負でない) 整数を格納する型です。WAVファイルのヘッダの各バイトをuint8_t値として扱うことができます。
  • int16_tは16ビット符号付き (正または負の) 整数を格納する型です。WAVファイル内の各オーディオサンプルをint16_t値として扱うことができます。

始め方

  1. GitHubアカウントを使用してide.cs50.ioにログインします。
  2. ターミナルウィンドウでwget https://cdn.cs50.net/2020/fall/labs/4/lab4.zipを実行し、実習の配布コードのZipファイルをダウンロードします。
  3. ターミナルウィンドウでunzip lab4.zipを実行し、そのZipファイルを解凍します。
  4. ターミナルウィンドウで、cd lab4を実行してディレクトリをlab4ディレクトリに変更します。

実装の詳細

volume.cの実装を完了して、サウンドファイルの音量を指定の係数で変更します。

  • このプログラムは、3つのコマンドライン引数を受け取ります。input は元のオーディオファイルの名前を表し、output は生成される新しいオーディオファイルの名前を表し、factor は元のオーディオファイルのボリュームをスケールする量を表します。
    • たとえば、factor が2.0の場合、プログラムはinputのオーディオファイルのボリュームを倍にし、新しく生成されたオーディオファイルをoutputに保存します。
  • プログラムは、最初に入力ファイルからヘッダーを読み取り、出力ファイルに書き込みます。このヘッダの長さは常に正確に44バイトであることを思い出してください。
    • volume.cは、ヘッダのバイト数に等しいHEADER_SIZEという名前の変数をすでに定義していることに注意してください。
  • 次に、プログラムは残りのデータを16ビット (2バイト) のサンプルを一度に1つずつWAVファイルから読み込みます。プログラムでは、各サンプルをファクターで乗算し、新しいサンプルを出力ファイルに書き込みます。
    • WAVファイルは16ビットの符号付き値をサンプルとして使用すると仮定します。実際には、WAVファイルのサンプルあたりのビット数はさまざまですが、この実習では16ビットのサンプルを想定しています。
  • mallocを使用するプログラムは、メモリーをリークしてはいけません。

ウォークスルー

ヒント

  • 入力ファイルから読み込むWAVファイルヘッダのデータを格納するために、バイトの配列を作成します。uint8_t型を使用してバイトを表すと、次のような構文でヘッダーのnバイトの配列を作成できます。
uint8_t header[n];

nはバイト数で置き換えます。その後、header を引数としてfread またはfwrite を使用して、ヘッダーを読み書きできます。

  • WAVファイルから読み込んだオーディオサンプルを保存する 「バッファ」 を作成することもできます。int16_t型を使用してオーディオサンプルを格納すると、次のような構文で変数bufferを作成できます。
int16_t buffer;

その後、&bufferを引数としてfread またはfwrite を使用して、バッファの読み込みまたは書き込みを行うことができます (変数のアドレスを取得するために&演算子が使用されることを思い出してください)。

  • fread とfwrite のドキュメントはこちらにあります。
    • 特に、どちらの関数も以下の引数を受け付けることに注意してください。
      • ptr: メモリ内でデータを格納する場所 (ファイルから読み取る場合) またはデータを書き込む場所 (ファイルにデータを書き込む場合) へのポインタ
      • size: データ項目のバイト数
      • nmemb:読み取りまたは書き込みを行うデータ項目数 (それぞれのバイトsize)
      • stream: 読み書きするファイルポインタ
    • ドキュメントによると、fread は正常に読み込まれたデータの数を返します。これは、ファイルの最後に達したことを確認する場合に便利です。

コードのテスト方法

プログラムは、次の例に従って動作する必要があります。

$ ./volume input.wav output.wav 2.0

output.wav (たとえば、ファイルブラウザでoutput.wavをダブルクリックするか、ターミナルからoutput.wavを開きます) を再生すると、input.wavの2倍の音量になります。

$ ./volume input.wav output.wav 0.5

output.wavを再生すると、input.wavの半分の音量になります。

解決方法がわかりませんか?

check50を使用して以下を実行し、コードの正確さを評価してください。ただし、コンパイルとテストは必ず自分で行ってください。

check50 cs50/labs/2021/x/volume

以下を実行し、style50を使用してコードのスタイルを評価します。

style50 volume.c

提出方法

次のコマンドを実行し、GitHubのユーザー名とパスワードを入力してログインします。セキュリティのため、パスワードには実際の文字ではなくアスタリスク (*) が表示されます。

submit50 cs50/labs/2021/x/volume