Введение
Нормальной русскоязычной информации по теме просто нет. Java-tutorials тоже оставляют желать лучшего. А архитектура javax.sound.sampled хоть и проста, но далеко не тривиальна. Поэтому свой первый пост на Хабре я решил посвятить именно этой теме. Приступим:
Воспроизведение звука
Тут всё более-менее просто. Импортируем javax.sound.sampled и поехали:
try {
File soundFile = new File("snd.wav"); //Звуковой файл
//Получаем AudioInputStream
//Вот тут могут полететь IOException и UnsupportedAudioFileException
AudioInputStream ais = AudioSystem.getAudioInputStream(soundFile);
//Получаем реализацию интерфейса Clip
//Может выкинуть LineUnavailableException
Clip clip = AudioSystem.getClip();
//Загружаем наш звуковой поток в Clip
//Может выкинуть IOException и LineUnavailableException
clip.open(ais);
clip.setFramePosition(0); //устанавливаем указатель на старт
clip.start(); //Поехали!!!
//Если не запущено других потоков, то стоит подождать, пока клип не закончится
//В GUI-приложениях следующие 3 строчки не понадобятся
Thread.sleep(clip.getMicrosecondLength()/1000);
clip.stop(); //Останавливаем
clip.close(); //Закрываем
} catch (IOException | UnsupportedAudioFileException | LineUnavailableException exc) {
exc.printStackTrace();
} catch (InterruptedException exc) {}
Регулятор громкости
Поигравшись со звуками, вы наверняка захотите иметь возможность программно изменять громкость звука. Java Sound API предоставляет такую возможность с фирменной кривотой.
//Получаем контроллер громкости
FloatControl vc = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
//Устанавливаем значение
//Оно должно быть в пределах от vc.getMinimum() до vc.getMaximum()
vc.setValue(5); //Громче обычного
Этот код нужно поместить между строчками clip.open(ais) и clip.setFramePosition(0).
Упрощаем процесс
Ну и наконец, чтобы вы не мучились, выкладываю класс для проигрывания звуков
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.FloatControl;
import javax.sound.sampled.LineEvent;
import javax.sound.sampled.LineListener;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.UnsupportedAudioFileException;
public class Sound implements AutoCloseable {
private boolean released = false;
private AudioInputStream stream = null;
private Clip clip = null;
private FloatControl volumeControl = null;
private boolean playing = false;
public Sound(File f) {
try {
stream = AudioSystem.getAudioInputStream(f);
clip = AudioSystem.getClip();
clip.open(stream);
clip.addLineListener(new Listener());
volumeControl = (FloatControl) clip.getControl(FloatControl.Type.MASTER_GAIN);
released = true;
} catch (IOException | UnsupportedAudioFileException | LineUnavailableException exc) {
exc.printStackTrace();
released = false;
close();
}
}
// true если звук успешно загружен, false если произошла ошибка
public boolean isReleased() {
return released;
}
// проигрывается ли звук в данный момент
public boolean isPlaying() {
return playing;
}
// Запуск
/*
breakOld определяет поведение, если звук уже играется
Если breakOld==true, о звук будет прерван и запущен заново
Иначе ничего не произойдёт
*/
public void play(boolean breakOld) {
if (released) {
if (breakOld) {
clip.stop();
clip.setFramePosition(0);
clip.start();
playing = true;
} else if (!isPlaying()) {
clip.setFramePosition(0);
clip.start();
playing = true;
}
}
}
// То же самое, что и play(true)
public void play() {
play(true);
}
// Останавливает воспроизведение
public void stop() {
if (playing) {
clip.stop();
}
}
public void close() {
if (clip != null)
clip.close();
if (stream != null)
try {
stream.close();
} catch (IOException exc) {
exc.printStackTrace();
}
}
// Установка громкости
/*
x долже быть в пределах от 0 до 1 (от самого тихого к самому громкому)
*/
public void setVolume(float x) {
if (x<0) x = 0;
if (x>1) x = 1;
float min = volumeControl.getMinimum();
float max = volumeControl.getMaximum();
volumeControl.setValue((max-min)*x+min);
}
// Возвращает текущую громкость (число от 0 до 1)
public float getVolume() {
float v = volumeControl.getValue();
float min = volumeControl.getMinimum();
float max = volumeControl.getMaximum();
return (v-min)/(max-min);
}
// Дожидается окончания проигрывания звука
public void join() {
if (!released) return;
synchronized(clip) {
try {
while (playing)
clip.wait();
} catch (InterruptedException exc) {}
}
}
// Статический метод, для удобства
public static Sound playSound(String path) {
File f = new File(path);
Sound snd = new Sound(f);
snd.play();
return snd;
}
private class Listener implements LineListener {
public void update(LineEvent ev) {
if (ev.getType() == LineEvent.Type.STOP) {
playing = false;
synchronized(clip) {
clip.notify();
}
}
}
}
}
Пользоваться очень просто, например:
Sound.playSound("sounds/hello.wav").join();
Форматы
Пару слов о поддержке форматов звуковых файлов: забудьте про mp3 и вспомните wav. Также поддерживаются au и aif.