« ◆粒子=波束論の怪しさ:波と粒子と | トップページ | JavaでPCMファイル波形データ読み書き:メモ »

△Javaで波形データ作成再生サンプル:メモ

メモです。

 Javaで波形データをbyte配列上に作成し、音として再生するサンプル

Javaで予め作り上げた波形データに基づくPCMクリップを再生するには、javax.sound.sampledパッケージの 次のクラスを使います。
  • AudioFormat
  • DataLine.info
  • AudioSystem
  • Clip
wavファイルのデータを取り扱う例を JavaでPCMファイル波形データ読み書きに置きました。

実際に440Hzのサイン波(サンプリング周波数44100hz 8bit)を2秒間鳴らすサンプルを載せます。

// Test01.java
import javax.sound.sampled.*;
class Test01 {
   public static void main(String[] args_){
      try{
         byte[] wave_data= new byte[44100*2];                      // @A-sta@
         double l1      = 44100.0/440.0;    // A 440hz
         for(int i=0;i<wave_data.length;i++){
            wave_data[i]= (byte)(110*Math.sin((i/l1)*Math.PI*2));
            }                                                      //@A-end@

         AudioFormat   frmt= new AudioFormat(44100,8,1,true,false);// @B-sta@
         DataLine.Info info= new DataLine.Info(Clip.class,frmt);
         Clip          clip= (Clip)AudioSystem.getLine(info);
         clip.open(frmt,wave_data,0,wave_data.length);             // @B-end@
         clip.start();

         Thread.sleep(100);while(clip.isRunning()) {Thread.sleep(100);}
         }
      catch(Exception e){e.printStackTrace(System.err);}
      }
   }

@A-sta@行~@A-end@行でbyte配列上に単純なサイン波のデータを作成しています。

@B-sta@行~@B-end@行が音を出す基本のジュゲム記述です。
4つのクラスはいずれも2行目のimportで使用可能となっています。

Clip.start()は非同期関数です。音の終了を46行目で待っています。
注意が必要なのが、start()を呼んだ直後ではisRunning()がtrueとならない 場合があることです。ここではまず100ミリ秒sleepした上でisRunning()を 呼んでいます。

コンパイル/実行は単純にコマンドラインから行うことができますが、 次のようなバッチファイルで動作させることが出来ます(Windowsの場合)。

:: Test01.bat
javac Test01.java
java  Test01
pause

参考までにAppletにしたものを置きます。

後半に記述してある「うなり」「ビブラート」「音階」もも含みます。
ちなみに、「うなり」で440Hz,vib:15Hzくらいにすると電話の呼び出し音のようになります。 「音階」にはビブラートが付いています。vib=0でビブラートは止まります。「音階つなぎ」では 音階と音階の間をグリッサンドのようにつなぎます。 「音階う」はサイン波の代わりに日本語の"う"の一波を繰り返しています。 他より音程を下げています。 倍音合成とfrmnt(フォルマント)合成では音程を1オクターブ下げています。

この仕組みを発展させたサンプル sample5.mp3▲「ん」「な行」「ま行」と「が」音声合成試験

 うなり

周波数の異なる波を重ねればうなりが得られます

         byte[] pcm_data= new byte[44100*3];// 
         double l1      = 44100.0/440.0;
         double l2      = 44100.0/445.0;
         for(int i=0;i<pcm_data.length;i++){
            pcm_data[i]=  (byte)(55*Math.sin((i/l1)*Math.PI*2));
            pcm_data[i]+= (byte)(55*Math.sin((i/l2)*Math.PI*2));
            }

 ビブラート

位相の進み方を揺らすとビブラート音が得られます。
         byte[] pcm_data= new byte[44100*4]; 
         double p1      = (440.0*Math.PI*2)/44100;
         double pv      = (5.0*Math.PI*2)/44100;
         double phase   = 0;
         double v_phase = 0;
         for(int i=0;i<pcm_data.length;i++){
            phase   += p1;
            v_phase += pv;
            double p= phase+2.0*Math.sin(v_phase);
            pcm_data[i]=  (byte)(110*Math.sin(p));
            }

 音階

基本の周波数に2のn/12乗をかけることにより半音ずつの音階を得ることができます。
全音/半音の並びを設定すればドレミファ音階を得ることができます。

         byte[] pcm_data= new byte[44100*4]; 
         double onkai[]={ -9,-7,-5,-4,-2,0,2,3 };// C,D,E,F,G,A,H,C
         double px[]   = new double[8];
         for(int i=0;i<8;++i){
            px[i]= (440*Math.pow(2.0,onkai[i]/12.0)*Math.PI*2)/44100;
            }
         double phase   = 0;
         for(int i=0;i<pcm_data.length;i++){
            phase   += px[(i/10000)%8];
            pcm_data[i]=  (byte)(110*Math.sin(phase));
            }

 フォルマント合成

単純なサイン波を重ねる形のフォルマント合成を行ってみます。
2倍音、3倍音と第1フォルマント、第2フォルマントを重ね"あ"っぽい 音を得ます。このプログラムの数値は適当です。

         byte[] pcm_data= new byte[44100*2];
         double f01 = 44100.0/220;
         double f02 = 44100.0/(220*2);
         double f03 = 44100.0/(220*3);
         double f04 = 44100.0/(220*4);
         double f05 = 44100.0/(220*5);
         double f06 = 44100.0/(220*6);
         for(int i=0;i<pcm_data.length;i++){
            double b  = (byte)(50*Math.sin((i/f01)*Math.PI*2));
            b        += (byte)(20*Math.sin((i/f02)*Math.PI*2));
            b        += (byte)(10*Math.sin((i/f03)*Math.PI*2)); <-第1フォルマント
            b        += (byte)(0 *Math.sin((i/f04)*Math.PI*2));
            b        += (byte)(20*Math.sin((i/f05)*Math.PI*2)); <-第2フォルマント
            b        += (byte)(20*Math.sin((i/f05)*Math.PI*2));
            pcm_data[i] = (byte)b;
            }

 音量調節

javax.sound.sampled.FloatControlをClipから取得し、音量調節を行うことが できます。
次のプログラムの断片はclipの生成時にFloatControlを取得し,UIのSlider値(0~100) が変化したときに音量をセットしています。setValueに与えるのはデシベル値です。

  FloatControl  control;
//  clip生成時
  control = (FloatControl)clip.getControl(FloatControl.Type.MASTER_GAIN);
//  JSliderイベント発生時
  control.setValue((float)(Math.log10(slVol.getValue()/100.0) * 20.0));

 ###

2011/7/12
サンプルアプレットを別HTMLから呼ぶ形だったものを、この記事で直接呼ぶ形に変更した。

2011/7/15
行番号付きソースコードがコピペ時にIE8最新版ではなぜか行番号も ペーストされるようになってしまったので、行番号無しに変更。
昔は大丈夫だったし、今も コピーの為のドラッグ中は行番号部は選択された形に見えない。


|

« ◆粒子=波束論の怪しさ:波と粒子と | トップページ | JavaでPCMファイル波形データ読み書き:メモ »

コメント

コメントを書く



(ウェブ上には掲載しません)




トラックバック


この記事へのトラックバック一覧です: △Javaで波形データ作成再生サンプル:メモ:

« ◆粒子=波束論の怪しさ:波と粒子と | トップページ | JavaでPCMファイル波形データ読み書き:メモ »