Linux + Java で音をならす

久しぶりにJavaを勉強しようと思い、Lubuntu13.04にopenjdk-7-jdkを入れたまま放置していたので、JDK8を入れ直すべく「kiy271の日記 インフラエンジニアの備忘録」の「Lubuntu 14.04でOracle JDKのインストール」を参考に操作した。

…という話を書いて、一部を変更しようと思ったら、間違えてきれいさっぱり記事が消えてしまった!思い出しながら、あちこち探しながら書き直すことにする。

どうやら13.04では対応していないようでJDK8はインストールできなかったので、まずはOSのアップグレードを…と思ったが、13.10へのオンラインアップグレードも終了していた。仕方がないので、とりあえずOSはそのまま、openjdk-7-jdkもそのままでお勉強することにする。

なお、新たに用意したLubuntu14.04では、上記のサイトで見た方法でJDK8をインストールすることができた。

sudo add-apt-repository ppa:webupd8team/java
sudo apt-get update
sudo apt-get install oracle-java8-installer


openjdk-7-jdkでも、基本的なプログラムはコンパイル・実行共に問題なかった。しかし、いざ音をならそうとすると「LineUnavailableException」などのエラーが出てうまくいかなかった。

「メモ用紙の裏」の「JavaSound on Linux」という記事を見ていると、どうやらLinuxでは音の再生にアプリケーションを使っているかもしれない、と思い、「aossというコマンドを使うらしい」と書かれているので、LXTerminalを起動して「aoss」と実行してみた。すると、「alsa-oss」をインストールしろと表示された。記事にはPulseAudioについても書かれているので、ついでにこれもインストールすることにした。

sudo apt-get install alsa-oss pulseaudio


さらに、この記事に書かれているままに以下をコピペしてホームディレクトリに.asoundrcとして保存した。

pcm.!default {
 type plug
 slave.pcm "dmixer"
}
#pcm.!plughw {
#  type plug
#  slave.pcm "dmixer"
#}
#pcm.dsp {
#  type plug
#  slave.pcm "dmixer"
#}
#pcm.dsp0 {
# type plug
# slave.pcm "dmixer"
#}
ctl.mixer0 {
 type hw
 card 0
}
pcm.dmixer {
 type dmix
 ipc_key 1024
 slave {
   pcm "hw:0,0"
   period_time 0
   buffer_time 0
   period_size 1024
   buffer_size 8192
   format S32_LE
   channels 2
   rate 44100
 }
 bindings {
   0 0
   1 1
 }
}
ctl.dmixer {
 type hw
 card 0
}


これで、「失言の多いプログラマ」の「JavaでWAVファイルを読む」を参考に以下のようにプログラムを書いてみた。

import javax.sound.sampled.*;
import java.io.*;

public class SoundPlayer {
 public static void main(String[] args) {
   try {
     File file = new File("alarm.wav");
     if(file.exists()) {
       AudioInputStream stream = AudioSystem.getAudioInputStream(file);
       byte[] buf = new byte[stream.available()];
       stream.read(buf, 0, buf.length);
       AudioFormat format = stream.getFormat();
       long nBytesRead = format.getFrameSize()*stream.getFrameLength();
       DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
       SourceDataLine line = (SourceDataLine)AudioSystem.getLine(info);
       line.open(format);
       line.start();
       line.write(buf, 0, (int)nBytesRead);
       line.drain();
       line.close();
     } else {
       System.out.println("ファイルが見つかりませんでした。");
     }
   } catch(Exception e) {
     e.printStackTrace();
   }
   System.exit(0);
 }
}


「SoundPlayer.java」として保存し、「javac SoundPlayer.java」とコンパイルして、同じディレクトリに音声ファイル「alarm.wav」を置いて、「java SoundPlayer」として実行すると、無事音がなった。

なぜ「alsa-oss」と「pulseaudio」を入れるだけで音がなるのだろう?いろいろ疑問が残るが、とりあえず音がなったので今回はOKとする。

ちなみに、Lubuntu14.04 + JDK8では、「alsa-oss」と「pulseaudio」を入れなくても音が再生できた。本当になぜ?まだまだ勉強が必要なようだ。

※後日追記
pulseaudioは必須なようだ。OSインストール時に「インストール中にアップデートをダウンロードする」と「サードパーティーのソフトウェアをインストールする」にチェックをつけると自動的に入るのかも…とも思ったが、チェックを付けてもダメなことも判明。おそらく何かべつのアプリケーションソフトウェアをインストールした際に依存で入ったのだろう…。


ここまでが、間違って消してしまったところ。

その後、さらにJavaで音を再生する方法を調べて回った。

Javaでの音の再生には、「TOYATAKU Web」の「音声管理」という記事によると、音を読み込みながら再生する「SourceDataLine」を使う方法と、短い音を事前にメモリ上に読み込んでおいて再生する「Clip」を使う方法の2種類があるらしい。

前回は「SourceDataLine」を使ったので、今回は「Clip」を使ってみることにする。

前回再生実験に用いた「alarm.wav」は、再生さえできればよいと考えてネット上で拾った時計の効果音でありとても短いため、実際の再生には「Clip」の方が向いているようだ。

「Clip」を利用した例はたくさんあったが、なぜかどれもエラーは出ないのに音が再生できなかった。いろいろと調べた結果、「人工知能に関する断創録」の「ClipでWAVE再生」の記事の上部から動作確認用のJARファイル「wave_engine.jar」をゲットすると、1回目だけは再生できた。一時停止したり、音が止まったあとはなぜか操作できなくなるのが気になったが…とにかく、そのJARファイルの中の「WaveEngine.java」と前回書いた「SoundPlayer.java」の2つを元に、以下のように書いたらやっと再生することができた。

import java.io.*;
import javax.sound.sampled.*;

class ClipPlayer {
 public static void main(String[] args) {
   try {
     File file = new File("alarm.wav");
     if(file.exists()) {
       AudioInputStream stream = AudioSystem.getAudioInputStream(file);
       AudioFormat format = stream.getFormat();
       DataLine.Info info = new DataLine.Info(Clip.class, format);
       Clip clip = (Clip)AudioSystem.getLine(info);
       clip.open(stream);
       clip.start();
       clip.drain();
       clip.stop();
       clip.close();
       stream.close();
     } else {
       System.out.println("ファイルが見つかりませんでした。");
     }
   } catch(Exception e) {
     e.printStackTrace();
   }
   System.exit(0);
 }
}


これを「ClipPlayer.java」として保存し、「javac ClipPlayer.java」でコンパイル、「alarm.wav」を同じディレクトリに置いておいて「java ClipPlayer」として実行すれば、無事音がなった。

なぜいろいろ公開している他の例では再生できないのだろう?わからないこと、勉強することはまだまだたっぷりあって、本当にキリがない。

コメント
コメントする








   
この記事のトラックバックURL
トラックバック

calendar

S M T W T F S
      1
2345678
9101112131415
16171819202122
23242526272829
3031     
<< July 2017 >>

selected entries

categories

archives

links

profile

書いた記事数:84 最後に更新した日:2016/09/11

search this site.

others

mobile

qrcode

powered

無料ブログ作成サービス JUGEM