프로그래밍 언어/JAVA

자바 오디오 다루기

· 코딩마이데이

자바의 오디오 API

자바는 응용프로그램에서 오디오를 재생하고 제어할 수 있는 오디오 API를 제공하며 다음 2가지 종류의 오디오 데이터를 다룰 수 있습니다.

  • 디지털 오디오(Digital Audio)
  • 미디(MIDI: Music Instrument Digital Interface) 데이터

디지털 오디오란 연주되고 있는 음악이나 사람의 목소리 등 아날로그 소리를 샘플링하여  디지털 데이터로 만든 오디오 데이터로, 움악 CD나 전화 목소리로 녹음한 WAVE 파일 등이 이에 해당합니다. 디지털 오디오를 다루는 자바 클래스와 인터페이스들은 javax.sound.sampled 패키지에 제공됩니다.

 

한편, 미디 데이터란 피아노, 바이올린, 드럼 등 악기의 소리를 낼 수 있는 특별한 장치(MIDI Device)에게, 어떤 악기를, 어느 높이로, 얼마의 시간동안 연주할지를 다시하는 데이터입니다. 미디 제어를 위한 클래스와 인터페이스는 javax.sound.midi 페키지에서 제공됩니다.

 

디지털 오디오 포맷

자바 오디오 API로 재생 가능한 디지털 오디오 포맷은 다음과 같습니다.

  • WAV, AU, AIFF, AIFC

오디오 클립과 오디오 재생

1. 오디오 클립 만들기

오디오를 재생하기 위해서는 먼저 오디오 클립(audio clip)을 만들어야 합니다. 오디오 클립의 가능은 자바의 Clip 인터페이스 객체를 통해 구현됩니다. 먼저 비어 있는 오디오 클립은 다음과 같이 생성합니다.

Clip clip = AudioSystem.getClip(); // AudioSystem 클래스의 static 메소드 getClip()

 

오디오 클립은 오디오 파일을 재생하기 전에 오디오 데이터를 미리 로딩해두고 제어하는 객체로서, 오디오 클립을 이용하면 오디오 파일 내 어느 위치든 재생가능하고 오디오 일부 혹은 전체를 반복 재생할 수도 있습니다.

 

2. 오디오 클립에 오디오 스트림 연결

오디오 파일로부터 오디오 데이터를 읽을 오디오 스트림 객체를 생성합니다. 다음은 애국가.wav 파일을 읽어들일 오디오 스트림 개겣를 생성하는 코드입니다.

File audioFile = new File("애국가.wav");
AudioInputStream audioStream = AudioStream.getAudioInputStream(audioFile);

 

그리고 나면, 다음과 같이 오디오 클립과 오디오 스트림을 연결합니다.

clip.open(audioStream); // 오디오 클립과 오디오 스트림 연결

 

이제, clip은 오디오 스트림으로부터 오디오 데이터를 받아 재생할 수 있는 상태가 됩니다.

 

3. 오디오 재생

Clip 클래스의 start() 메서드를 호출하면 오디오 재생을 시작합니다.

clip.start(); // 오디오 재생 시작

 

오디오 재생, 중단을 제어하는 Clip 메서드는 다음과 같습니다.

void open(AudioInputStream stream) 
	// 오디오 클립은 stream에 존재하는 오디오의 형식과 데이터를 인식하고, 재생할 수 있는 준비를 갖춘다.
void start()
	// 현재 프레임 위치에서 오디오 클립을 재생하고, 처음 실행될 때 프레임 위치는 0
void stop()
	// 재생중인 오디오 클립의 재생을 중단한다.
void setFramePosition(int frames)
	// 오디오 샘플 내에 재생할 프레임의 위치 지정, 프레임의 시작 번호는 0이다.
void loop(int count)
	// 현재 프레임의 위치에서 시작하여 count만큼 반복 재생, count 값이 LOOP_CONTINUOUSLY이면 무한 반복한다.
void close()
	// 오디오 클립의 모든 자원을 반환한다.

 

오디오 재생/중지

import javax.sound.sampled.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;

public class AudioEx extends JFrame {
    private JButton btns[] = { new JButton("play"),
        new JButton("stop"),
        new JButton("play again")};
    private Clip clip;

    public AudioEx() {
        setTitle("오디오 제어");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setSize(300, 150);
        Container c = getContentPane();
        c.setLayout(new FlowLayout());

        MyActionListener al = new MyActionListener();
        for (int i = 0; i < btns.length; i++) {
            c.add(btns[i]);
            btns[i].addActionListener(al); // 버튼에 Action 리스너 등록
        }
        setVisible(true);
        loadAudio("audio/애국가1절.wav");
    }

    private void loadAudio(String pathName) {
        try {
            clip = AudioSystem.getClip(); // 비어있는 오디오 클립 만들기
            File audioFile = new File(pathName); // 오디오 파일의 경로명
            AudioInputStream audioStream = AudioSystem.getAudioInputStream(audioFile); // 오디오 파일로부터
            clip.open(audioStream); // 재생할 오디오 스트림 열기
        } catch (LineUnavailableException e) {
            e.printStackTrace();
        } catch (UnsupportedAudioFileException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    class MyActionListener implements ActionListener {
        public void actionPerformed(ActionEvent e) {
            switch (e.getActionCommand()) {
                case "play": clip.start(); break; // 오디오 재생 시작
                case "stop": clip.stop(); break;
                case "play again":
                    clip.setFramePosition(0); // 재생 위치를 첫 프레임으로 변경
                    clip.stop(); // 오디오 재생 시작
                    break;
            }
        }
    }

    public static void main(String[] args) {
        new AudioEx();
    }
}

 

[실행결과]

 

 

오디오 클립에 Line 이벤트 처리

오디오 클립(Clip 객체)은 오디오가 재생되는 도중 여러 상황에서 Line 이벤트가 발생합니다. 이것은 Clip 클래스가 Line 클래스를 상속받았기 때문입니다.

 

Line 이벤트와 LineListener 인터페이스

오디오가 재생을 시작할 때, 재생이 중단되었을 때, 오디오 클립이 닫혔을 때, 오디오 클립 객체에 Line 이벤트가 발생합니다. Line 이벤트를 처리하는 리스너는 LineListener 인터페이스이며, Line 이벤트가 발생하면 다음 메소드가 호출됩니다.

public void update(LineEvent e)
	// 오디오가 재생을 시작할 때, 재생이 중단되었을 때, 오디오 클립이 딛혔을 때 호출됩니다.

 

LineEvent 객체

LineEvent 객체는 다음 메서드를 통해 이벤트에 대한 여러 정보를 제공합니다.

line getLine()
	// 이벤트가 발생하는 오디오 클립 객체(Clip은 Line 인터페이스 상속 받음)
long getFramePosition()
	// 오디오 내에 이벤트가 발생한 프레임 위치(0부터 시작)
LineEvent.Type getType()
	// 이벤트 종류로 다음 4가지 값 중 하나 리턴
	LineEvent.Type.OPEN: 오디오 클립이 열릴 때(Clip의 open() 호출시)
	LineEvent.Type.START: 재생이 시작될 때(Clip의 start() 호출시)
	LineEvent.Type.STOP: 재생이 중단될 때(Clip의 stop()이나 끝까지 재생되었을 때)
	LineEvent.Type.CLOSE: 오디오 클립이 닫히고 모든 자원이 반환되었을 때(Clip의 close() 호출시)

 

오디오 클립 객체에 Line 이벤트 리스너 달기

Clip의 addLineListener() 메서드를 이용하여 다음과 같이 리스너를 등록합니다.

clip.addLineListener(new MyLineListener());

 

 

오디오 연주가 끝나면 컨텐트팬의 배경색을 ORANGE 색으로 만들기

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

public class LineEventEx extends JFrame {
    private Clip clip;
    private String song="audio/애국가1절.wav";
    private JLabel label=new JLabel(song);

    public LineEventEx() {
        setTitle("애국가 1절 연주");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        Container c = getContentPane();
        c.setLayout(new FlowLayout());
        c.setBackground(Color.YELLOW);
        c.add(label);
        setSize(300,150);
        setVisible(true);
        loadAudio(song);
    }

    private void loadAudio(String pathName) {
        try {
            File audioFile = new File(pathName); // 오디오 파일의 경로명
            final AudioInputStream audioStream = AudioSystem.getAudioInputStream(audioFile); // 오디오 파일로부터

            clip = AudioSystem.getClip(); // 비어있는 오디오 클립 만들기
            clip.addLineListener(new LineListener() {
                public void update(LineEvent e) {
                    if (e.getType() == LineEvent.Type.STOP) { // clip.stop()이 호출되거나 재생이 끝났을 때
                        try {
                            getContentPane().setBackground(Color.ORANGE);
                            label.setText(song + " 연주 끝!");
                            audioStream.close();
                        } catch (IOException e1) {
                            e1.printStackTrace();
                        }
                    }
                }
            });
            clip.open(audioStream); // 재생할 오디오 스트림 열기
            clip.start(); // 재생 시작
        }
        catch (LineUnavailableException e) { e.printStackTrace(); }
        catch (UnsupportedAudioFileException e) { e.printStackTrace(); }
        catch (IOException e) { e.printStackTrace(); }
    }


    public static void main(String [] args) {
        new LineEventEx();
    }
}

 

[실행결과]

노래 시작
노래 끝

'프로그래밍 언어 > JAVA' 카테고리의 다른 글

표현식 사용하기  (0) 2025.10.01
탭팬  (0) 2025.09.18
컬러 다이얼로그  (0) 2025.09.15
파일 다이얼로그  (0) 2025.09.12
팝업 다이얼로그  (1) 2025.09.09