Работа с аудиофайлами стандартными средствами Java
Среди стандартных средств для работы со звуком существует интерфейс AudioClip.
Экземпляр объекта, реализующего этот интерфейс можно получить методом getAudioClip(), который, кроме того, загружает звуковой файл, а затем пользоваться методами play(), loop() и stop() этого интерфейса для проигрывания музыки.
Для применения данного же приема в приложениях в класс Applet введен статический метод newAudioclp(URL address), загружающий звуковой файл, находящийся по адресу address, и возвращающий объект, реализующий интерфейс Audioclip. Его можно использовать для проигрывания звука в приложении, если конечно звуковая система компьютера уже настроена.
Наиболее популярными форматами, используемыми в приложениях или апплетах, являются WAV, AU и SND.
Ниже приведен код апплета.
package javaaudio1;
import java.applet.Applet;
import java.applet.AudioClip;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.logging.Level;
import java.util.logging.Logger;
public class AudioApplet1 extends Applet
{
public void init()
{
// Создаем объект AudioClip
// с помощью метода getAudioClip класса Applet,
// в который подаем ссылку на аудиофайл.
AudioClip ac;
Try
{
ac = getAudioClip(new URL("http://localhost/audio/javaaudio.wav"));
ac.play();
}
catch (MalformedURLException ex)
{
Logger.getLogger(AudioApplet1.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
В состав виртуальной машины Java, входящей в SUN J2SDK начиная с версии 1.3, включено устройство, проигрывающее звук, записанный в одном из форматов AU, WAVE, AIFF, MIDI, преобразующее, микширующее и записывающее звук в тех же форматах.
Для работы с этим устройством созданы классы, собранные в пакеты javax.sound.sampled, javax.sound.midi, javax.sound.sampled.spi и javax.sound.midi.spi. Перечисленный набор классов для работы со звуком получил название Java Sound API.
Проигрыватель звука, встроенный в JVM, рассчитан на два способа записи звука: моно и стерео оцифровку (digital audio) с частотой дискретизации (sample rate) от 8 000 до 48 000 Гц и аппроксимацией (quantization) 8 и 16 битов, и MIDI-последовательности (sequences) типа 0 и 1.
Оцифрованный звук должен храниться в файлах типа AU, WAVE и AIFF. Его можно проигрывать двумя способами.
Первый способ описан в интерфейсе Clip. Он рассчитан на воспроизведение небольших файлов или неоднократное проигрывание файла и заключается в том, что весь файл целиком загружается в оперативную память, а затем проигрывается.
Второй способ описан в интерфейсе SourceDataLine. Согласно этому способу файл загружается в оперативную память по частям в буфер, размер которого можно задать произвольно.
Перед загрузкой файла надо задать формат записи звука в объекте класса AudioFormat. Конструктор этого класса: AudioFormat(float sampleRate, int sampleSize, int channels, boolean signed, boolean bigEndian) требует знания частоты дискретизации sampleRate (по умолчанию 44 100 Гц), аппроксимации sampleSize, заданной в битах (по умолчанию 16), числа каналов channels (1 — моно, по умолчанию 2 — стерео), запись чисел со знаком, signed == true, или без знака, и порядка расположения байтов в числе bigEndian. Такие сведения обычно неизвестны, поэтому их получают косвенным образом из файла. Это осуществляется в два шага.
На первом шаге необходимо получить формат файла статическим методом getAudioFiieFormato класса AudioSystem, на втором — формат записи звука методом getFormato класса AudioFiieFormat.
После того как формат записи определен и занесен в объект класса AudioFormat, в объекте класса DataLine. infо собирается информация о входной линии (line) и способе проигрывания clip или SourceDataLine. Далее следует проверить, сможет ли проигрыватель обслуживать линию с таким форматом. Затем надо связать линию с проигрывателем статическим методом getLine () класса AudioSystem. Потом создать поток данных из файла — объект класса Audioinputstream. Из этого потока тоже можно извлечь объект класса AudioFormat методом getFormat ().
Можно задать проигрывание n раз подряд методом loop(n) или бесконечное число раз методом loop (Clip.LOOP_CONTINUOUSLY) . Перед этим необходимо установить начальную n и конечную m позиции повторения методом setLoopPoints(n, m).
Ниже приведен листинг программы, использующей интерфейс Clip.
package javaaudio2;
import java.awt.Button;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.Clip;
import javax.sound.sampled.DataLine;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Main
{
public static void main(String[] args)
{
final PlayAudio pa = new PlayAudio("D:\\javaaudio.wav");
// Создаем объект главного окна приложения.
JFrame f = new JFrame("Audio");
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
Button start = new Button("Play");
start.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent arg0)
{
pa.play();
}
});
Button stop = new Button("Stop");
stop.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent arg0)
{
pa.stop();
}
});
panel.add(start);
panel.add(stop);
f.add(panel);
f.setSize(300,100);
f.setLocation(200,200);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}
class PlayAudio
{
Clip line;
public PlayAudio(String file)
{
try
{
// Создаем объект, представляющий файл.
File f = new File(file);
// Получаем информацию о способе записи файла.
AudioFileFormat aff = AudioSystem.getAudioFileFormat(f);
// Получаем информацию о способе записи звука.
AudioFormat af = aff.getFormat();
// Собираем всю информацию вместе,
// добавляя сведения о классе.
DataLine.Info info = new DataLine.Info(Clip.class, af);
// Проверяем, можно ли проигрывать такой формат.
if (!AudioSystem.isLineSupported(info))
{
System.err.println("Line is not supported.");
System.exit(0);
}
// Получаем линию связи с файлом.
line = (Clip) AudioSystem.getLine(info);
// Создаем поток байтов из файла.
AudioInputStream ais = AudioSystem.getAudioInputStream(f);
// Открываем линию.
line.open(ais);
}
catch (Exception e)
{
System.err.println(e);
}
}
public void play()
{
line.start();
}
public void stop()
{
line.stop();
}
}
Второй способ, использующий методы интерфейса SourceDataLine, требует предварительного создания буфера произвольного размера.
package javaaudio3;
import java.io.File;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;
public class Main
{
public static void main(String[] args)
{
PlayAudioLine pal = new PlayAudioLine("D:\\javaaudio.wav");
pal.play();
}
}
class PlayAudioLine
{
String file;
PlayAudioLine(String file)
{
this.file = file;
}
public void play()
{
AudioInputStream ais = null;
SourceDataLine line = null;
byte[] b = new byte[2048]; // Буфер данных
try
{
File f = new File(file);
// Создаем входной поток байтов из файла f
ais = AudioSystem.getAudioInputStream(f);
// Извлекаем из потока информацию о способе записи звука
AudioFormat af = ais.getFormat();
// Заносим эту информацию в объект info
DataLine.Info info = new DataLine.Info(SourceDataLine.class, af);
// Проверяем, приемлем ли такой способ записи звука
if (!AudioSystem.isLineSupported(info))
{
System.err.println("Line is not supported.");
System.exit(0);
}
// Получаем входную линию
line = (SourceDataLine) AudioSystem.getLine(info);
// Открываем линию
line.open(af);
line.start();
// Ждем появления данных в буфере
int num = 0;
// Заполняем буфер
while ((num = ais.read(b)) != -1)
{
line.write(b, 0, num);
}
// Проигрываем остаток файла
line.drain();
// Закрываем поток
ais.close();
}
catch (Exception e)
{
System.err.println(e);
}
line.close();
}
}
Проигрывание MIDI-файлов
В MIDI-файлах хранится последовательность (sequence) команд для секвенсора (sequencer) — устройства для записи, проигрывания и редактирования MlDI-последовательности, которым может быть физическое устройство или программа. Последовательность состоит из нескольких дорожек (tracks), на которых записаны MIDI-события (events). Каждая дорожка загружается в своем канале (channel). Обычно дорожка содержит звучание одного музыкального инструмента или запись голоса одного исполнителя или запись нескольких исполнителей, микшированную синтезатором (synthesizer).
Для проигрывания MIDI-последовательности в простейшем случае надо создать экземпляр секвенсора, открыть его и направить в него последовательность, извлеченную из файла. После этого следует начать проигрывание методом start (). Закончить проигрывание можно методом stop(), "перемотать" последовательность на начало записи или на указанное время проигрывания
— методами setMicrosecondPositionf(long mcs) или setTickPosition(long tick).
Ниже приведен пример простейшего проигрывателя MIDI-файлов.
package javaaudiomidi;
import javax.sound.midi.*;
import java.io.*;
public class Main
{
public static void main(String[] args)
{
JavaAudioMidi jam = new JavaAudioMidi("D:\\javaaudio.mid");
jam.play();
}
}
class JavaAudioMidi
{
String file;
public JavaAudioMidi(String file)
{
this.file = file;
}
public void play()
{
try
{
File f = new File(file);
// Получаем секвенсор по умолчанию
Sequencer sequencer = MidiSystem.getSequencer();
// Проверяем, получен ли секвенсор
if (sequencer == null)
{
System.err.println("Sequencer is not supported.");
System.exit(0);
}
// Открываем секвенсор
sequencer.open();
// Получаем MIDI-последовательность из файла
Sequence seq = MidiSystem.getSequence(f);
// Направляем последовательность в секвенсор
sequencer.setSequence(seq);
// Начинаем проигрывание
sequencer.start();
}
catch (Exception e)
{
System.err.println(e);
}
}
}
Варианты заданий
Контрольные вопросы
1. Назовите способы добавления изображений.
2. Какие фильтры можно применять к методу drawImage для обработки Image?
3. Каково предназначение класса FilteredlmageSource?
4. Перечислите наиболее популярные форматы, используемые в приложениях или апплетах.
5. Что такое Java Sound API?