제가 예전에 자바스크립트의 MIDIjs라는 라이브러리를 이용해 미디 플레이어를 만든 적이 있습니다.

 

여기서 다른 스마트폰에서는 테스트해보지 않았지만 아이폰에서는 사파리 창을 닫으면 재생이 되지 않습니다. 컴퓨터에서는 문제가 없습니다만, 아이폰에서는 제가 사용하면서 이 점이 매우 불편했습니다. 그런데 외부 라이브러리를 사용했기 때문에 이 문제를 제가 컨트롤 할 수가 없었습니다.

이번에 아마존 웹 서비스 배포 연습을 할 목적으로 새 프리티어 EC2 계정을 만들었는데 여기다가 자바(스프링 부트)+리눅스를 이용한 미디플레이어를 새로 만들어볼 생각입니다. 먼저 만들었던 것에서 디자인과 기능은 그대로 사용하고, 미디 파일을 받아오는 방식만 바꿀 예정입니다.

먼저, 첫 단계로 Timidity++LAME 인코더를 이용해 미디 파일을 mp3로 바꾸는 메소드만 하나 만들어 보겠습니다. 경로를 입력하면 Timidity++를 이용해 미디 파일을 wav 파일로 바꾼 뒤, 이 wav 파일을 LAME을 사용해 mp3로 바꿉니다.

 

Timidity++, LAME 설치

Homebrew가 있는 경우

brew install timidity
brew install lame

아마존 AMI에서 설치하는 방법은 링크를 참고해주세요.

 

TimidityRunner 클래스 작성


import java.io.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class TimidityRunner {
// 여기로 보낼 때 루트 패스 포함해서 보냄.
public static File convertMidiToMp3(String midiPath) throws IOException {
Integer lastIndexOfDot = midiPath.lastIndexOf(".");
String wavPath = midiPath.substring(0, lastIndexOfDot) + ".wav";
String mp3Path = midiPath.substring(0, lastIndexOfDot) + ".mp3";
String[] midiCmd = {"/usr/local/bin/lame/timidity", midiPath, "-o", wavPath, "-Ow"};
ProcessBuilder midiBuilder = new ProcessBuilder(midiCmd);
midiBuilder.redirectErrorStream(true);
Process midiProcess = midiBuilder.start();
InputStream is = midiProcess.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = null;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
System.out.println("==========================================");
// wav 파일 생성 후
File wavFile = new File(wavPath);
if(wavFile.exists() && wavFile.length() > 0) {
String[] lameCmd = {"/usr/local/bin/lame", wavPath, mp3Path};
ProcessBuilder lameBuilder = new ProcessBuilder(lameCmd);
lameBuilder.redirectErrorStream(true);
Process lameProcess = lameBuilder.start();
is = lameProcess.getInputStream();
reader = new BufferedReader(new InputStreamReader(is));
line = null;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
// mp3 파일 있는지 체크
File mp3File = new File(mp3Path);
if(mp3File.exists() && mp3File.length() > 0) {
System.out.println(">> Convert succeeded.");
return mp3File;
} else {
throw new IllegalStateException("Failed to convert mp3 file.");
}
} else {
throw new IllegalStateException("Failed to convert wave file.");
}
}
public static String getHash(String path) throws IOException, NoSuchAlgorithmException {
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
FileInputStream fileInputStream = new FileInputStream(path);
byte[] dataBytes = new byte[1024];
Integer nRead = 0;
while((nRead = fileInputStream.read(dataBytes)) != -1) {
messageDigest.update(dataBytes, 0, nRead);
}
byte[] mdBytes = messageDigest.digest();
StringBuffer stringBuffer = new StringBuffer();
for(Integer i = 0; i < mdBytes.length; i++) {
stringBuffer.append(Integer.toString((mdBytes[i] & 0xff) + 0x100, 16)).substring(1);
}
return stringBuffer.toString();
}
public static void main(String[] args) throws IOException, NoSuchAlgorithmException {
String midiPath = "/Users/example/Documents/midi/canyon.mid";
System.out.println(TimidityRunner.getHash(midiPath));
TimidityRunner.convertMidiToMp3(midiPath);
}
}

  • 미디 파일의 경로를 입력하면 같은 디렉토리에 wav 파일과 mp3파일을 만들고, mp3파일의 자바 File 객체를 반환합니다.
  • ProcessBuilder를 사용하면 터미널 명령어를 실행할 수 있습니다. 프로세스의 .getInputStream()은 현재 프로세스에서 터미널 화면에 표시되는 내용을 가져인풋 스트림 형태로 가져오고 이것을 BufferedReader를 통해 자바 실행창에 표시합니다.
  • <span class="pl-smi">ProcessBuilder</span><span> midiBuilder </span><span class="pl-k">=</span><span> </span><span class="pl-k">new</span><span> </span><span class="pl-smi">ProcessBuilder</span>(midiCmd); 커맨드를 입력할 때에는 커맨드와 매개변수를 분리해서 스트링 배열 (또는 다중 스트링 파라미터)로 입력해야 합니다.
    예) 터미널에서 ls ~/ 로 입력하는 경우 new ProcessBuilder(new String[]  {"ls", "~/"}); 로 입력
  • Timidity++에서 미디 파일을 wav로 변환하는 명령은 timidity [midi_path] -o [wave_path] -Ow 입니다.
  • wav로 변환이 되었다면 mp3 변환을 준비합니다.
  • wav 파일을 mp3로 변환하는 명령은 lame [wave_path] [mp3_path]입니다.

 

문의 | 코멘트 또는 yoonbumtae@gmail.com




0개의 댓글

답글 남기기

Avatar placeholder

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다