필자는 eclipse에서 먼저 테스트 구동을 하고 Android Studio로 넘어가려고 했으나...
eclipse에서 사용하는 javax.sound.midi는 안드로이드상에서는 사용이 안되고
Android Studio에서 기본 제공하는 MIDI 라이브러리를 사용해야 된다고 한다
🔻 안드로이드 공식 MIDI 라이브러리
https://source.android.com/devices/audio/midi
🔻 공식 라이브러리를 사용한 프로젝트
https://github.com/philburk/android-midisuite
내 수준에서는 코드가 너무 어렵고 원하는 코드만 가져오기에는 클래스끼리 연관성이 높기 때문에 함부로 건드리기 쉽지 않았다.
eclipse에서 사용하던 코드를 사용하기 위해 깃허브에서 안드로이드용 javax.sound.midi 라이브러리를 구해서 사용했다.
🔻 kshoji github
https://github.com/kshoji/javax.sound.midi-for-Android
🔻 Gradle, Manifest 설정 참고
https://github.com/kshoji/javax.sound.midi-for-Android/wiki/Use-USB-MIDI-features
🐻 Manifest
<uses-feature android:name="android.hardware.usb.host" />
🐻 App 단위 Gradle
repositories {
maven { url 'https://github.com/kshoji/javax.sound.midi-for-Android/raw/master/javax.sound.midi/repository' }
maven { url 'https://github.com/kshoji/USB-MIDI-Driver/raw/master/MIDIDriver/snapshots' }
}
implementation 'jp.kshoji:javax-sound-midi:0.0.4:@aar'
implementation 'jp.kshoji:midi-driver:0.1.5:@aar'
//선언부
UsbMidiSystem usbMidiSystem;
//인식 프로세스가 동작될 액티비티에서 초기화가 이루어져야함
usbMidiSystem = new UsbMidiSystem(this);
usbMidiSystem.initialize();
일단 키보드와 스마트폰을 연결해야하므로 usb midi-c타입 케이블이 필요하다.
정확히 말하자면 usb b cable이 필요하다(흔히 굴러다니는 프린터케이블임)
전자피아노가 midi를 호환하는지 먼저 봐야한다.
테스트에서는 Galaxy S10 과 CASIO CDP-S90 키보드를 연결했다.
🔻 eclipse 상에서 동작시킨 코드는 stack overflow를 참조했다.
https://stackoverflow.com/questions/6937760/java-getting-input-from-midi-keyboard
애플리케이션의 동작은 MainActivity에서 midiRecord 클래스를 호출하는 형식이다.
AsyncTask를 이용하여 백그라운드에서 작업하며 onProgressUpdate를 통해 변경된 결과를 반영시킬수 있다.
public class RecordAudio extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
MidiDevice device;
MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo();
while(started){
for (int i = 0; i < infos.length; i++) {
try {
device = MidiSystem.getMidiDevice(infos[i]);
System.out.println(infos[i]);
List<Transmitter> transmitters = device.getTransmitters();
for (int j = 0; j < transmitters.size(); j++) {
// create a new receiver
transmitters.get(j).setReceiver(
new MidiInputReceiver(device.getDeviceInfo().toString()));
}
Transmitter trans = device.getTransmitter();
trans.setReceiver(new MidiInputReceiver(device.getDeviceInfo().toString()));
device.open();
System.out.println(device.getDeviceInfo() + " Was Opened");
publishProgress();
} catch (MidiUnavailableException e) {
Log.e("AudioRecord", "Recording Failed");
}
}
}
return null;
}
public class MidiInputReceiver implements Receiver {
public String name;
public MidiInputReceiver(String name) {
this.name = name;
}
public void send(MidiMessage msg, long timeStamp) {
byte[] aMsg = msg.getMessage();
// take the MidiMessage msg and store it in a byte array
//변수를 여기서 바꾸어주었으면 좋겠다 이말이죠.
//aMsg[0] = velocity
//aMsg[1] = note
//aMsg[2] = pressed much
mds1 = (String.valueOf(aMsg[0]));
mds2 = (String.valueOf(aMsg[1]));
mds3 = (String.valueOf(aMsg[2]));
System.out.println(aMsg[0]);
System.out.println();
}
public void close() {
}
}
코드를 간단히 설명하자면
midi 장치를 열어서 정보를 읽어들이면
MidiDevice device;
MidiDevice.Info[] infos = MidiSystem.getMidiDeviceInfo();
담은 내용을 가지고 MidiInputRecevier 클래스를 호출뒤 transmitter로 전달한다.
for (int j = 0; j < transmitters.size(); j++) {
// create a new receiver
transmitters.get(j).setReceiver(
new MidiInputReceiver(device.getDeviceInfo().toString()));
}
이때 호출되는 값은 다음과 같다.
byte[] aMsg = msg.getMessage();
//aMsg[0] = velocity : 누름 세기
//aMsg[1] = note : 음계
//aMsg[2] = pressed much : 지속시간
요 세개의 값만 잘 활용한다면 신디사이저 구현도 어렵지 않을듯...