Wookim

MIDI device with JavaScript (웹미디) 본문

programming language/Javascript

MIDI device with JavaScript (웹미디)

개발자인 경우 2020. 11. 10. 15:42

토이프로젝트 진행중에 

Javascript에서 MIDI 장비의 입력 이벤트를 받을 수 있는지 궁금해졌다.

 

 

MIDI란? 

  • 뮤직컬 인스트루먼트(악기) 디바이스 인터페이스 (musical instrument device interface)

 

마스터 키보드란?

  • MIDI의 한종류로 피아노같은 것인데 컴퓨터에 연결하여 쳤을 때 입력을 컴퓨터에게 디지털 신호로 전달한다.

 

마스터 키보드 (https://reverb.co.kr/product/impactlx49) 연결 후 연주해도 소리가 나진 않는다. 프로그램을 사용해야함.


 

필자의 상황은

컴퓨터에 마스터 키보드가 연결되어 있고 토이 프로젝트의 웹 브라우저가 실행되고 있을 때, 

건반을 눌렀을 때, 이벤트를 감지하는것이다.

 

 

 

방법이 없을까 찾던 중 web midi를 이용하면 가능하다는 것을 알게되어 정리한다.

 

 


Web MIDI

javascript를 이용해 웹브라우저에서 midi의 입력을 처리하기 위한 방법으로 web midi를 사용한다고 한다.

 

필자는 간단하고 빠르게 여러분의 MIDI 기기를 웹브라우저에서 입력 이벤트를 인식하기 위한 방법을 설명하겠다.

 

 

document.addEventListener("DOMContentLoaded", function(){
 // 코드 내용
}

 

자 우선 WebMidiEx.js 파일을 만들고 위와 같이 작성하자.

 

위 코드의 내용은 도큐먼트에 이벤트를 추가하는 것이다.

세부 내용은 다른 전문가들에게...

 

    //코드 내용
    if (navigator.requestMIDIAccess) {
        alert('This browser supports WebMIDI!');
    } else {
        alert('WebMIDI is not supported in this browser.');
    }

위 코드는 //코드 내용 이라는 부분에 작성한 코드이다.

 

브라우저 호환성을 체크할 때 navigator를 이용한다고 한다. 

navigator를 이용해 해당 브라우저가 WebMIDI를 제공하는지 여부를 확인할 수 있다.

 

    navigator.requestMIDIAccess().then(onMIDISuccess, onMIDIFailure);

    function onMIDIFailure() {
        console.log('Could not access your MIDI devices.');
    }

    function onMIDISuccess(midiAccess) {
        for (var input of midiAccess.inputs.values()){
            input.onmidimessage = getMIDIMessage;
        }
    }
    
    function getMIDIMessage(midiMessage) {
        console.log(midiMessage);
        if (48 <= midiMessage.data[1] && midiMessage.data[1] <= 64){


            var promise = document.querySelector(`audio[data-key="${midiMessage.data[1]}"]`).play();

            if (promise !== undefined) {
                promise.then(_ => {
                    promise.play();
                }).catch(error => {
                    console.log(error);
                }); 
            }
        }
    }

 

겁먹지 말길... 하나하나 설명하겠다.

이전에 사용한 navigator.requestMIDIAccess는 사실 함수다. 이 네비게이터에 requestMIDIAccess()함수가 존재하는 지 확인한 것이고, 존재한다면 

    navigator.requestMIDIAccess().then(onMIDISuccess, onMIDIFailure);

요렇게 사용한 것이다.

 

.then(onMIDISuccessonMIDIFailure);  이부분은 프로미스를 이해해야 하는 부분이다.

이해가 가지 않는다면, 

joshua1988.github.io/web-development/javascript/promise-for-beginners/

 

자바스크립트 Promise 쉽게 이해하기

(중급) 자바스크립트 입문자를 위한 Promise 설명. 쉽게 알아보는 자바스크립트 Promise 개념, 사용법, 예제 코드. 예제로 알아보는 then(), catch() 활용법

joshua1988.github.io

이분의 글을 읽어보길. 깔끔하게 설명해주셨다.

 

간단하게 설명하자면

navigator.requestMIDIAccess() 함수는 프로미스를 리턴한다.

매개변수 onMIDISuccess, onMIDIFailure는 결과에 따라 작업 사항을 예약하는 것이라 생각하면 될듯.

 

requestMIDIAccess() -> 실행 -> 완료 -> 성공 : onMIDISuccess() 호출 

                                                 -> 실패 : onMIDIFailure() 호출

 

정확한지는 모르겠으니.. 잘 모른다면 위글을 꼭 읽자

 


 

제일 중요한 부분을 보자

    function onMIDISuccess(midiAccess) {
        for (var input of midiAccess.inputs.values()){
            input.onmidimessage = getMIDIMessage;
        }
    }
    
    function getMIDIMessage(midiMessage) {
        console.log(midiMessage);
        if (48 <= midiMessage.data[1] && midiMessage.data[1] <= 64){


            var promise = document.querySelector(`audio[data-key="${midiMessage.data[1]}"]`).play();

            if (promise !== undefined) {
                promise.then(_ => {
                    promise.play();
                }).catch(error => {
                    console.log(error);
                }); 
            }
        }
    }

간단하게 설명하자면 

 

MIDI기기와 브라우저가 연결 -> MIDI 입력 -> midiMessage 담아 전달 -> getMIDIMessage(midiMessage) 로직 실행.

 

 

getMIDIMessage(midiMessage) 함수가 실행되면 midiMessage가 콘솔에 찍힌다. 

(웹디버거 f12에서 콘솔 찍힌것을 열어서 살펴볼것. 이작업은 꼭 하길 )

 

살펴보면 midiMessage.data가 있는데 int 배열이다.

[0, 1, 2] 이런식의 배열이고 각 index마다 의미하는 데이터는 다음과 같다.

 

[command, note, velocity] 

 

커맨드와 밸로시티는 찾아시길.

note가 중요한데, 마스터키보드라면 해당 note값이 누른 건반의 id라 생각하면된다.

 

즉 해당 값으로 어떤 건반을 눌렀는지 알수 있다.

 

if (48 <= midiMessage.data[1] && midiMessage.data[1] <= 64)

위 코드를 보면 48~64 이내의 범위로 note값을 지정했는데,

필자의 마스터 키보드의 가운데 도 부터 1옥타브위 미까지의 숫자를 의미한다.

 

즉 도~미 까지 키보드를 눌렀다면 실행되는 if문이라 생각하면된다.

 

var promise = document.querySelector(`audio[data-key="${midiMessage.data[1]}"]`).play();
if (promise !== undefined) {
    promise.then(_ => {
        promise.play();
    }).catch(error => {
        console.log(error);
    }); 
}

필자는 이 부분이 제일 좀 어려웠다.

변수에 html 엘리먼트의 play()를 매핑시켰다.

 

사실 그냥 <audio ,,,,> 태그 객체에 접근해서 play() 시키고 싶었는데

구글의 정책상 자동 재생은 막았다고 한다.

(video가 자동 재생되도 audio는 나오지 않도록 해야한다고 한다. 이게 audio에도 적용된듯)

내가 이해하긴 그런데, 자세한 내용은 비디오나 오디오 파일 재생시 문제점을 검색해보길 추천한다.

 


 

필자의 토이 프로젝트

github.com/wookim789/chord_walk_front_react

위 깃허브에 작업중인 필자의 토이프로젝트 코드가 있다.

공개하긴 민망해서 비공개였는데... 필요하다면 참고해보시길.

nodejs를 다를줄 안다면 npm start 하면 리엑트 웹서버가 실행된다.

 

실행화면은 이렇고 마우스로 키보드를 클릭해보고 마스터 키보드가 연결되있다면 한번 연주해보시길..

 

아직 많이 부족한점이 많지만 재밌는 프로젝트다. 진행중이다.

 

 

   개선해야 할점

1. 프로미스 이해도, 활용법 익히기

2. 마우스로 클릭하지 않으면 마스터 키보드로 연주해도 소리가 안되는 점 개선

3. 키를 동시에 여러게 입력했을 때, 소리 동시에 나도록 수정

 

 

끝으로 보고 따라한 사이트이다.

www.smashingmagazine.com/2018/03/web-midi-api/

 

Getting Started With The Web MIDI API — Smashing Magazine

Is it possible to use digital musical instruments as browser inputs? With the Web MIDI API, the answer is yes! The best part is, it’s fairly quick and easy to implement and even create a really fun project.

www.smashingmagazine.com

사실 필자의 글보다 이글을 읽는게 훠어얼신 이해가 빠를 수도 있다....

다만 무엇을 하려는지 명확하게 이해하고 보면 더 도움이 될까바 정리해 둔다.

 

 

 

읽어주셔서 감사합니다.

피드백은 환영합니다!!

 

'programming language > Javascript' 카테고리의 다른 글

javascript 글로벌 변수  (0) 2019.01.02
Comments