マウスによる演奏

  1. 内容

    グリッド上でマウを移動して演奏します。グリッドの値がランダムに変化するため、同じ位置でも異なる音になります。グリッドの値は色で表現されるため、視覚的にも楽しむことができます。

  2. 手法

    1. 音の再生

      次のようにAudioClipを利用します。再生可能な au ファイルは4または8KHzでサンプリングされた音声です。
       sounds = new AudioClip[nsound];
      //auファイルを読み込む
       sounds[i] = getAudioClip(getCodeBase(),"sound.au");
       sounds[themenote[i]-1].play();//演奏

      auファイルは、音声編集ツールで wav から変換できます(フリーソフト:WavePaseri、Google で 「ベクタ」 WavwPaseri で検索します。解凍後インストールなしで実行可能)。

      音はこんな波形です。プツンと切れずに滑らかに落ち、かなり余韻を残しています。

    2. アプレットの引数
      htmlからアプレットに引数を渡すことができます。パラメータの名前、パラメータを受け取る変数の名前とその型、既定値を設定できます。ここでは、音の数:nsound、.auファイルのパス:dir、音(色)を入れ替える時間:Speed をパラメータとして取得します。
      アプレットタグでは、次のように指定します。
      <APPLET
       CODE = "harp.Applet1.class"
       NAME = "Harp">
       <PARAM NAME = "nsound" VALUE = "12">
       <PARAM NAME = "dir" VALUE = "audio">
       <PARAM NAME = "Speed" VALUE = "100">
      </APPLET>

  3. プロジェクト

    1. 主なデータ

      1. 音ファイル
        audioディレクトリに12種の C3、D、..C4、D、E、F、G の高さの音が TONE1.AU、..、TONE12.AU として保存されています。

      2. AudioClip sounds[]
        音ファイルを読み込む変数です。

      3. noteno[][]、notecolor[nsound][3];
        最初、noteno[nsound][nsound]の各行に、nsound=12までの音符を順に並べて記録します。この状態で、マウスを左右に移動すると、音階を順に演奏します。また、各音の値の対し notecolor[][] で色を設定しており、各格子は番号に対応する色で表示します。

      4. アプレットのパラメータ
        nsound:音の数、最大12
        dir:音ファイルのディレクトリを指定します
        speed:音を入れ替える間隔を指定します

    2. 主なメソッド

      1. init
        getParameter("nsound")でキーに対応するパラメータの値を受け取ります。その後に getMedia(); で、音声ファイルを AudioClip[] に読み込み、notecolorset(); で、音符のカラー情報を color[] に設定します。

      2. start()
        実行の初期化をします。これは、init()の後で呼び出されます。ここでは、スレッドの開始、および、initnoteno();で、noteno[][];を初期化します。

      3. paint()
         カラー格子を表示します。最初、countで番号を数えながら themanote[]の音(テーマ音)を順に再生します。その後、noteno[][];の音符の色で各格子を表示します。また、現在マウスが位置する格子(nox,nowy)を白で表示します。
         スレッドで、再表示をするとき、changeRect()で、格子の音符をランダムに変更します。

      4. getMedia()
        音声ファイルを読み込みます。音声ファイルの名前を合成しながら、読み込んでいます。try..catchでエラー処理をしています。
            public void getMedia(){//.auファイルの読み込み
                int i;
                sounds = new AudioClip[nsound];
                for(i=0;i<nsound;i++){
                    try{
                      sounds[i] = getAudioClip(getCodeBase(),dir+"/TONE"+(i+1)+".AU");
                    }catch(Exception e){
                        System.out.println(e);}
                }
            }

      5. changeaRect()
        Math.random() で 0..1 の乱数を発生します。この値が音符の数以上なら、音符を初期値に戻します。そうでないとき、格子の音符を乱数に変更します。したがって、確率的に格子の値がランダムに入れ替わるため、表示される格子の色が変化します。

            public void changeaRect(){//格子の色を変更
                int i,x;
                int    floor,room; //段とマス
        
                x= (int)(Math.random() * nsound*6)+1; //乱数を生成
                floor=x % nsound;  //何段めかを調べる
                room= (int)(Math.random() * nsound); //左から何番の格子か
                x= (int)(Math.random() * (nsound));
                if(x>=floor){ //ノートナンバーは格子のナンバーとする
                     noteno[floor][room]=room;
                }
                else{ //ノートのナンバーを変更する
                     noteno[floor][room]=(int)(Math.random() * 12); //ノートナンバー
                }
            }

      6. mouseMove(Event event,int x,int y)
        マウスの移動に伴い実行されるメソッドです。現在マウスの位置する格子をnowx.nowyに記録し、マウスの格子上の位置が前の位置(beforex,beforey)と変化した場合、その格子の音符を演奏します。格子の値はランダムに変化するため、同じ位置でも異なる音になります。

            public boolean mouseMove(Event event,int x,int y) {
        
                //System.out.println("mouseMove:dim"+dim.width+"nowx:"+nowx);
                nowx=x/(dim.width/nsound);
                if(nowx>nsound-1) nowx=nsound-1;
                nowy=y/(dim.height/nsound);
                if(nowy>nsound-1) nowy=nsound-1;
        
                if(beforex==nowx && beforey==nowy){//マウスの移動なし
                return true;
                }
                else{
                 sounds[noteno[nowy][nowx]].play();
                 beforex=nowx;beforey=nowy;
                 }
                return true;
            }

      7. paint()
        描画処理を行います。スレッドで書き換えを行いますが、最初の12回までは、テーマ音を流します。
          public void paint(Graphics g) {
            if(counter==12){
            changeaRect();
            int i,i1;
              for(i1=0;i1<nsound;i1++){
                for(i=0;i<nsound;i++){
                  if(i1==nowy && i==nowx) g.setColor(Color.white);
                  else g.setColor(color[noteno[i1][i]]);
                  g.fillRect(i*dim.width/nsound,i1*dim.height/nsound,
                  dim.width/nsound,dim.height/nsound);
                }
              }
            }
            else if(counter<12){
            //最初にテーマの演奏、以後格子をランダムに変更しながら表示
              theme(counter);
              counter++;
            }
          }

      8. update()
        paint()の再描画時に呼び出されるメソッドで、これを指定すると、ちらつきが軽減されます。

      9. run()
         sleep()で一定時間休みながら、repaint(); を呼び出し再描画します。

    3. ソース

       ソースはこちらにあります。
           ソース

  4. 実行

    実行すると、最初テーマ曲が演奏されます。次に、格子の音符に対応する色で塗られた格子が表示され、この色がランダムに変化します。マウスで格子を移動すると、格子の音符に対応する音が再生されます。



  5. ダウンロード

    このプロジェクトで利用している音ファイルは下記からダウンロードできます。次の行をクリックして、audio.exeファイルを適当なフォルダに保存します。
     ダウンロード開始
    このファイルは自己解凍型の圧縮ファイルです。このファイルを実行すると指定したフォルダに音ファイルが生成されます。