Lab4:Volume

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

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

$ ./volume INPUT.wav OUTPUT.wav 2.0

INPUT.wavは元のオーディオファイルの名前、OUTPUT.wavは指定された係数(例えば2.0)でスケーリングされた音量を持つオーディオファイルの名前です。

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値として扱うことができます。

始め方

VS Codeを開きます。

ターミナルウィンドウ内をクリックすることから始めて、それからcdを実行します。
その後プロンプトは次のようになっていることがわかります。

$

ターミナルウィンドウの内側をクリックし、次のように入力します。

wget https://cdn.cs50.net/2021/fall/labs/4/volume.zip

その後にEnterを押すと、volume.zipというZIPがあなたのCodespaceにダウンロードされます。wgetと次のURLの間にあるスペースや、その他の文字を見落とさないように注意してください。

次に

unzip volume.zip

を実行して、volumeというフォルダを作成します。
ZIPファイルは不要になったため、

rm volume.zip

を実行し、プロンプトで “y “に続いてEnterで応答すると、ダウンロードしたZIPファイルが削除されます。

次に

cd volume

の後にEnterを押して、そのディレクトリに移動する(つまり、開く)。これでプロンプトは以下のようになります。

volume/ $

すべて成功した場合は、次のように実行します。

ls

すると、volume.c ファイルと input.wav ファイルが表示されます。

もし問題が発生した場合は、もう一度同じ手順を踏んで、どこが間違っていたかを確認してください

実装の詳細

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を使用するプログラムは、メモリーをリークしてはいけません。

ウォークスルー

このビデオは、コースがまだコードを書くためにCS50 IDEを使用していたときに記録されたものです。インターフェイスはあなたのCodespaceと異なるように見えますが、2つの環境の動作はほぼ同じであるはずです!

ヒント

  • 入力ファイルから読み込む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をcontrolキーを押しながらクリックし、ダウンロードを選択し、コンピュータのオーディオプレーヤーでファイルを開きます。) を再生すると、input.wavの2倍の音量になります。

$ ./volume input.wav output.wav 0.5

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

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

check50 cs50/labs/2022/x/volume

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

style50 volume.c

提出方法

ターミナルで、以下を実行して提出してください。

submit50 cs50/labs/2022/x/volume