1. 준비
MP3를 다룰 수 있는 여러 라이브러리가 존재하지만, Java에서는 대표적으로 JLayer가 사용된다.
1.1 JLayer 라이브러리 추가
<http://www.javazoom.net/javalayer/javalayer.html>
위 사이트에서 소스코드, jar 파일 등을 다운받은 뒤, Java Build Path에 폴더 내 jar 파일을 추가해주면 된다.
2. 음악 데이터를 담을 클래스 정의
JLayer 라이브러리 내 Player 클래스를 사용하면 손 쉽게 음악을 재생할 수 있다. 그러나 음악 파일을 분석할 수 있도록 해야 하므로 라이브러리의 기존 코드를 참고하여 클래스를 재정의한다.
2.1 음악 파일 내부
음악은 영상처럼 여러 개의 프레임으로 이루어져 있으며, 한 프레임은 여러 개의 sample 값들로 이루어져 있다.
Sample 클래스 정의
한 프레임의 Sample 값들을 저장하기 위한 클래스를 정의한다.
xxxxxxxxxxclass Sample { private short[] buffer; private int size; public Sample(short[] buf, int s) { buffer = buf.clone(); size = s; } public short[] GetBuffer() { return buffer; } public int GetSize() { return size; }}Frame의 VO 클래스로, sample 값들을 생성자로 입력받아 저장한다.
Player 클래스 정의
음성 파일을 불러와 해당 음성 파일에 대한 정보를 저장하고 재생할 수 있는 클래스를 정의한다.
xxxxxxxxxxclass MyPlayer { public static final int BUFFER_SIZE = 44100000; private Decoder decoder; private AudioDevice out; private ArrayList<Sample> samples; private short[][] musicbuffers; private int size; public MyPlayer(String path) { Open(path); } public boolean IsInvalid() { return (decoder == null || out == null || samples == null || !out.isOpen()); } .. ..}생성자로부터 파일의 경로를 받아 해당 파일을 decoding하여 samples 변수에 저장한다.
xxxxxxxxxx public boolean Open(String path) { Close(); try { decoder = new Decoder(); out = FactoryRegistry.systemRegistry().createAudioDevice(); samples = new ArrayList<Sample>(BUFFER_SIZE); size = 0; out.open(decoder); GetSamples(path); musicbuffers = GetMusicBuffers(); } catch(JavaLayerException e) { decoder = null; out = null; return false; } return true;}public void Close() { if((out != null) && !out.isOpen()) out.close(); size = 0; samples = null; out = null; decoder = null;}
아래 코드는 JLayer의 decoder 함수를 이용하여 decoding한 뒤 Buffer 값을 얻어낸다.
xxxxxxxxxxprotected boolean GetSamples(String path) { if(IsInvalid()) return false; try { Header header; SampleBuffer sb; FileInputStream in = new FileInputStream(path); Bitstream bitstream = new Bitstream(in); if((header = bitstream.readFrame()) == null) return false; while(size < BUFFER_SIZE && header != null) { sb = (SampleBuffer)decoder.decodeFrame(header, bitstream); samples.add(new Sample(sb.getBuffer(), sb.getBufferLength())); size++; bitstream.closeFrame(); header = bitstream.readFrame(); } } catch(FileNotFoundException e) { return false; } catch(BitstreamException e) { return false; } catch(DecoderException e) { return false; } return true;}
3. 음악 데이터 출력하기
위에서 정의한 MyPlayer 클래스 내에 음악을 재생하는 함수를 정의한다.
xxxxxxxxxxpublic void Play() { if(IsInvalid()) return; try { for(int i=0; i < size; i++) { short[] buffers = samples.get(i).GetBuffer(); out.write(samples.get(i).GetBuffer(), 0, samples.get(i).GetSize()); } out.flush(); } catch(JavaLayerException e) { }}미리 담아둔 sample 데이터를 AudioDevice 객체를 통해 출력하면 음악을 재생할 수 있다. 이 때 세부적으로 데이터를 처리하기 위해 MyPlayer의 멤버변수 musicbuffers을 초기화하여 사용할 수 있다.
xxxxxxxxxx.. ..short[] buffers = musicbuffers[i];out.write(buffers, 0, samples.get(i).GetSize());.. ..이제 메인함수에서 객체를 생성한 뒤 Play 함수를 호출하면 음악이 재생된다.
xxxxxxxxxxpublic static void main(String[] args) { MyPlayer mp = new MyPlayer("C:\\psycho.mp3"); mp.Play(); mp.Close()}
4. Thread를 사용하여 음악 재생
위의 방법은 음악 재생 중간에 음악을 중단시키거나 다른 일을 할 수 없다. 따라서 Thread 클래스를 정의하여 이를 해결하자.
xxxxxxxxxxclass MusicPlayer extends Thread { MyPlayer mp; public MusicPlayer(MyPlayer player) { mp = player; } public void run() { mp.Play(); }}public class MainClass { public static void main(String[] args) { MyPlayer mp = new MyPlayer("C:\\psycho.mp3"); MusicPlayer player = new MusicPlayer(mp); player.start(); Scanner scan = new Scanner(System.in); scan.nextLine(); mp.Close(); }}
댓글