この 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倍にすると、ボリュームは半分になります。
型
これまでのところ、int
、bool
、char
、double
、float
、long
など、Cにはさまざまな型があることを見てきました。stdint.h
と呼ばれるヘッダファイルの中には、整数のサイズ (ビット単位) と符号 (符号付きまたは符号なし) を非常に正確に定義することを可能にする多くの他の型の宣言があります。この実習では、特に2つのタイプが役立ちます。
uint8_t
は8ビットの符号なし (すなわち負でない) 整数を格納する型です。WAVファイルのヘッダの各バイトをuint8_t
値として扱うことができます。int16_t
は16ビット符号付き (正または負の) 整数を格納する型です。WAVファイル内の各オーディオサンプルをint16_t
値として扱うことができます。
始め方
- GitHubアカウントを使用してide.cs50.ioにログインします。
- ターミナルウィンドウで
wget https://cdn.cs50.net/2020/fall/labs/4/lab4.zip
を実行し、実習の配布コードのZipファイルをダウンロードします。 - ターミナルウィンドウで
unzip lab4.zip
を実行し、そのZipファイルを解凍します。 - ターミナルウィンドウで、
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