課題 (05:サウンド)
作業について
今回の課題は以下のパッケージに作成してください。
パッケージの名前 |
---|
j1.lesson05 |
作成するクラスの名前は問題ごとに指示があります。下記を参照してください
課題の提出方法については下記を参照してください。
また、別のコンピューター上に移動する際には、下記を参考にプログラムを持ち帰ってください。
新しい内容
音声を取り扱う
この課題は、音声を取り扱うための仕組みを使います。最初に、コンピューターで音声を取り扱うための方法を紹介します。
音声は物理現象であり連続した信号として表現されます。連続した信号は、アナログ信号とばれテープレコーダなどで録音、再生することができました。コンピューターで音声を扱うためには、このアナログ信号を連続していない値の集合(離散値)、つまりディジタル信号に変換する必要があります。
この変換は、「標本化」と「量子化」によって行われます。最初に行われる「標本化」では、アナログ信号を一定の時間間隔で採取し離散値の集合に変換します。「標本化」は「サンプリング」とも呼ばれます。「量子化」は、標本化されたアナログ信号を近似的に数値化します。つまりアナログの値に近い値を割り当てるということです。このディジタル化の仕組みは、音声だけではなく静止画や動画にも適用されています。音声では一定の時間間隔で標本を採取しますが、画像では一定の距離で標本を採取するという違いがあります。
次にアナログ信号とディジタル信号の音データの例を図で示します。
アナログ信号では、連続した時刻で値をとります。一方、ディジタル信号では離散的な時刻で値をとっています。また、図のように音データは0を基準点とした交流波形となります。
アナログ信号により近いディジタル信号をつくるためには、標本化と量子化をより細かく行うことが必要です。標本化を細かくするには、一定時間の標本化の回数を多くすればより精度が高くなります。1秒あたりの標本の回数は、「標本化周波数」として定義されます。標本化周波数が大きければ、標本化の精度が高いということです。量子化では、数値の範囲が広いとより多くの数値でアナログ信号を表現することができるため精度が高くなります。
標本化周波数の単位は、「Hz(ヘルツ)」です。例えば、5Hzと10Hzのディジタル信号を比較すると、標本化周期が小さく(標本化する間隔が小さく)1秒間の標本化数が10個である10Hzのほうがより精度が高いといえます。
標本化では、対象となるアナログ信号の2倍以上の標本化周波数を用いれば、もとの信号を再現できることが知られています。この性質は「シャノンの標本化定理」(あるいは単に「標本化定理」)と呼ばれています。
人間は、20Hzから20kHz(20キロヘルツ=20,000ヘルツ)までの範囲を音として聞くことができるといわれます。シャノンの標本化定理で考えると、20kHzの2倍である40kHz以上で音声を標本化すれば、人の耳ではもとの音と標本化した音が同じ音として聞こえることになります(同時に量子化の精度も高くするする必要はあります)。例えば、音楽CDは標本化周波数が44.1kHzに設定されています。これは、音楽を忠実に再現するという目的のためにシャノンの標本化定理に基づいた設定であるといえます。
WAVEファイル
コンピューターでは、ディジタル化した音データをオーディオファイルとして扱います。オーディオファイルには、WAV、AU、MP3など様々な形式があります。課題では、Windowsコンピューターで一般に利用されるWAVEファイルを扱うことにします。
ディジタル化したデータは大量になるため、圧縮した形式も多く用いられています。例えば、44kHzで標本化したデータの数は、1秒間に44,000個となります。3分の曲に換算すると 44,000 * 3 * 60 = 7,920,000 で、約800万個のデータが必要になります。この例からも、ディジタル化することで大量のデータをコンピューターが取り扱っていることが理解できるかと思います。
WAVEファイルは、標本化周波数や音データを保持しています。この講義では、音データを-1.0より大きく、1.0未満の範囲の数値で扱います。
音声データを加工する
この課題では、音声データを加工します。音声データは、WAVEファイルに記録されているので、すでに例題で実施したようにWAVEファイルを読み込んで準備をします。読み込んだ情報から音テータを取り出して加工し、元の所に戻す処理を繰り返すことで音データ全体を加工することができます。
標本化された音データは、量子化によって近似的に数値化されていました。量子化の細かさを量子化精度と呼び、表現できる数値のステップ数を表します。
量子化精度はビットを単位とします。例えば、量子化精度が8ビットであれば、256段階(2の8乗)で量子化することになります。量子化精度が16ビットであれば、65536段階(2の16乗)で量子化することになります。
量子化の精度を高めれば、それだけ元の音に近い状態で音声をデジタル化できますが、それだけコンピューター上では情報が大きくなってしまいます。通常のコンピューターでは1バイトを8ビットとして取り扱います。量子化精度が16ビット(音楽CDと同様)である場合、サンプル1つにつき2バイトの容量が必要です。標本化周波数が44.1kHz、量子化精度が16bitで、1日分の音声情報は、実に7GB以上の容量が必要になります。
音データをもとに描画できる波形の振幅は「音の大きさ(音量レベル)」を表しています。波が大きければ音量レベルが高く、音は大きいことになります。音データを一定の比率で操作することで、この音の大きさを変えることができます。なお、ここで説明している「音の大きさ」は、増幅(ボリューム操作)によって音が大きく聞こえる(あるいは小さく聞こえる)という意味ではなく、標本化された音データの中での相対的な大きさであることに注意してください。つまり、ボリューム操作のように音を、ボリュームの最大までいくらでも大きく出来るということではありません。
音データを読み出す
音データを読み込みWAVEファイルとして保存する方法を紹介します。このプログラムは、WAVEファイルを読み込み、音データを取り出します。取り出した音データは、そのままもとの所に格納し(つまり、音データはそのままです)、別のWAVEファイルとして保存します。
この機能を試すために、次のファイルをダウンロードしてコンピューター上に保存しておいてください (ブラウザによりますが、右クリックしてコンテキストメニューから「対象をファイルに保存」などを選択します) 。
利用するWAVEファイル |
---|
first.wav |
これ以降「利用するWAVEファイル」と表記されているところでは、上記の操作を行い、ファイルをコンピューター上に保存してから利用してください。
この課題は、「クリップ(Clip)」という音声を取り扱うための仕組みを使って出題しています。これまでと同じやり方でパッケージ「j1.lesson05」にクラス「ReadWriteSample」を作成して下さい。
クラスを作成したら、次のような骨組みを作成します。これまでの教材との違いは、プログラムの先頭に「import gpjava.Clip;」という音声を利用するための1行を追加している点です。
package j1.lesson05; import gpjava.Clip; public class FirstSound { public static void main(String[] args) { new FirstSound().start(); } void start() { Clip sound = Clip.load(); for (int i = 0; i < sound.getSampleCount(); i++) { double sample = sound.getSample(i); sound.setSample(i, sample); } sound.save(); } }
プログラムでは、void start() {…}の最初の行で「Clip.load();」という、音声データを読み出す命令を書いています。この命令で、ファイルを選択するダイアログが表示されます。ダイアログでは、先ほどダウンロードしたWAVEファイルを指定してください。選択されたファイルがWAVEファイルでない場合は、エラーとなります。
読みだした音声は、「sound」という名前の変数に記憶させています。音声データは文字列などと同様に、変数に記憶させられますが、このときの型には「Clip」という名前を指定します。
この変数に対して、プログラムでは4種類の操作を行っています。
- サンプルデータの個数を確認する: sound.getSampleCount()
- 特定の位置のサンプルを確認する: sound.getSample(i)
- 特定の位置のサンプルを変更する: sound.setSample(i, data)
- 音声を保存する: sound.save()
下記は見慣れないJavaの文法ですが、これは「音声に含まれるサンプルを順に処理する」というプログラムの書き方です。
for (int i = 0; i < sound.getSampleCount(); i++) { double sample = sound.getSample(i); sound.setSample(i, sample); }
これは「for文」というJavaの文法で、より詳しくは繰り返しの回で紹介します。
このブロックに含まれている「double sample = sound.getSample(i);」という命令は、音声からサンプルデータを一つ取り出して、変数sampleに記憶させています。この講義では、それぞれのサンプルデータは-1.0から+1.0の間の値を取ります。
次に「sound.setSample(i, sample);」という命令では、先ほど取り出したサンプルデータを、変数「sample」に記憶させた内容で書き換えています。
今回の例では「sound.getSample()」から「sound.setSample()」の間で、変数「sample」の内容を特に書き換えていないため、同じ内容をそのまま書き出すプログラムになっています。
しばらくは、
for (int i = 0; i < sound.getSampleCount(); i++) { double sample = sound.getSample(i); ... (ここでsampleの値を変更する) sound.setSample(i, sample); }
というパターンで音声に含まれるすべてのサンプルを書き換えられると考えてください。たとえば、以下のように書くとすべてのサンプルを0.8倍します。
double sample = sound.getSample(i); sample = sample * 0.8; sound.setSample(i, sample);
最後の「sound.save();」という命令は、読み出して加工した音声を別の場所に保存する命令です。先ほどと同様にダイアログが表示されますので、保存先とファイル名を入力して保存してください。
保存した音声を確認する
保存したファイルはコンピューターにインストールされているAudacityというソフトウェアで確認できます。
Audacityがインストールされていない場合は、 http://audacity.sourceforge.net/ からダウンロードして利用します。実験環境はWindows 7なので、1.3以上のバージョン(2011年3月の時点でベータ版)を使います。
なお、Audacityは2011/04/01現在、 http://code.google.com/p/audacity/downloads/list からもダウンロードできるようです。Windows 7を利用している場合には、「Audacity 1.3.? for Windows 2000/XP/Vista/7 (.zip)」をダウンロードして展開し、中身の「audacity」という実行ファイルをダブルクリックして起動します。
Audacityを起動したら、上部の「ファイル」から「開く…」をクリックし、先ほど保存したファイルを選択します。
WAVEファイルが読み込まれ、次のような画面が表示されます。
拡大、縮小して波形の特徴を観察してください。
音声を再生する前に、必ず「音声を再生する前に」に目を通してください。作成した音声によっては、再生すると人や機械にダメージを与える場合があります。
- コラム:
問題
1. 音の大きさを下げる
作成するクラスの名前 |
---|
VolumeDown |
利用するWAVEファイル |
---|
first.wav |
ダウンロードした音声ファイルの、すべてのサンプル値を50%小さくするプログラムを作成してください。
作成したWAVEファイルを、Audacityで表示して確認してください。
2. 音の大きさを上げる
作成するクラスの名前 |
---|
VolumeUp |
利用するWAVEファイル |
---|
first.wav |
ダウンロードした音声ファイルの、すべてのサンプル値を20%大きくするプログラムを作成してください。
ただし、サンプル値が-1.0以下になる場合には、その値を-1.0に変更してください。また、サンプル値が+1.0以上になる場合には、その値を+1.0に変更してください。
このように、量子化の範囲を超えた値を正しい値に直すような操作を、クリッピングと呼びます。
作成したWAVEファイルを、Audacityで表示して確認してください。