Copyright © 2015-2025 World Wide Web Consortium. W3C® liability, trademark and permissive document license rules apply.
일부 사용자 에이전트에는 신시사이저, 키보드 및 기타 컨트롤러, 드럼 머신과 같은 음악 장치가 호스트 컴퓨터 또는 장치에 연결되어 있다. 널리 채택된 Musical Instrument Digital Interface (MIDI) 프로토콜은 전자 악기, 컨트롤러 및 컴퓨터가 서로 통신하고 동기화할 수 있게 한다. MIDI는 오디오 신호를 전송하지 않는다. 대신 음악 음표에 대한 이벤트 메시지, 볼륨, 비브라토 및 패닝 같은 매개변수에 대한 컨트롤러 신호, 템포를 설정하기 위한 큐와 클록 신호, 그리고 시스템별 MIDI 통신(예: 신시사이저별 패치 데이터를 원격으로 저장하기 위한 것)을 보낸다. 이 동일한 프로토콜은 쇼 컨트롤, 조명 및 특수 효과 제어와 같은 비음악적 용도를 위한 표준이 되었다.
이 명세는 MIDI 프로토콜을 지원하는 API를 정의하며, 웹 애플리케이션이 클라이언트 시스템에서 MIDI 입력 및 출력 장치를 열거하고 선택하며 MIDI 메시지를 보내고 받을 수 있게 한다. 이는 사용자의 시스템에서 사용할 수 있는 MIDI 장치에 대한 저수준 접근을 제공하여 음악 MIDI 애플리케이션뿐만 아니라 비음악 MIDI 애플리케이션도 가능하게 하려는 것이다. Web MIDI API는 음악이나 컨트롤러 입력을 의미론적으로 설명하려는 것이 아니다. 이는 MIDI 입력 및 출력 인터페이스의 동작 방식과 MIDI 메시지를 보내고 받는 실제적인 측면을 노출하도록 설계되었으며, 그러한 동작이 의미론적으로 무엇을 뜻하는지 식별하지 않는다(예: 컨트롤러 값을 변경하거나 우연히 G#7 코드를 나타내는 일련의 note-on 메시지를 보내는 것 외에, "비브라토를 20Hz로 변조한다" 또는 "G#7 코드를 연주한다"와 같은 의미).
일부 사용자에게 "MIDI"는 Standard MIDI Files 및
General MIDI와 동의어가 되었다. 이것은 이 API의 의도가 아니다.
단순히 .SMF 파일을 재생하는 사용 사례는 이
명세의 범위에 속하지 않는다(예를 들어 HTML
audio
요소가 지원해야 할 다른 형식으로 간주될 수 있다).
Web MIDI API는 MIDI에 응답하는 장치,
예를 들어 컨트롤러, 외부 신시사이저 또는 조명 시스템에 대한
직접 접근을 가능하게 하려는 것이다.
Web MIDI API는 또한 물리적 버튼, 노브 및
슬라이더가 있는 외부 하드웨어 컨트롤러(키보드, 기타 또는 관악기
컨트롤러 같은 음악 컨트롤러뿐만 아니라)를 사용하여
웹 애플리케이션을 제어하는 등, MIDI 컨트롤러 입력에 응답할 수 있는
새로운 종류의 웹 애플리케이션을 가능하게 하도록 명시적으로 설계되었다.
Web MIDI API는 또한 웹 플랫폼의 다른 API 및 요소, 특히 Web Audio API와 함께 사용될 것으로 예상된다. 이 API는 또한 Apple의 CoreMIDI 및 Microsoft의 Windows MIDI API 같은 다른 시스템의 MIDI API 사용자에게 익숙하도록 의도되었다.
이 절은 이 문서가 발행된 시점의 상태를 설명한다. 현재 W3C 발행물 목록과 이 기술 보고서의 최신 개정판은 https://www.w3.org/TR/의 W3C 기술 보고서 색인에서 찾을 수 있다.
이 문서는 Audio Working Group이 Recommendation 트랙을 사용하여 작업 초안으로 발행하였다.
작업 초안으로 발행되었다는 것은 W3C와 그 회원들이 승인했음을 의미하지 않는다.
이 문서는 초안 문서이며 언제든지 다른 문서로 업데이트되거나, 대체되거나 폐기될 수 있다. 이 문서를 진행 중인 작업이 아닌 것으로 인용하는 것은 부적절하다.
이 문서는 W3C 특허 정책에 따라 운영되는 그룹에 의해 작성되었다. W3C는 해당 그룹의 산출물과 관련하여 이루어진 모든 특허 공개의 공개 목록을 유지한다. 그 페이지에는 특허 공개에 대한 지침도 포함되어 있다. 개인이 그 개인이 Essential Claim(s)을 포함한다고 믿는 특허에 대한 실제 지식을 가지고 있는 경우, 그 정보는 W3C 특허 정책의 6절에 따라 공개해야 한다.
이 문서는 2023년 11월 03일 W3C Process Document의 적용을 받는다.
이 절은 비규범적이다.
Web MIDI API 명세는 웹 개발자가 MIDI 장치를 열거하고, 조작하고, 접근할 수 있는 수단을 정의한다. 예를 들어 다른 장치가 연결될 수 있는 하드웨어 MIDI 포트를 제공하는 인터페이스와 USB-MIDI 명세를 지원하는 USB 장치가 이에 해당한다. MIDI를 위한 Web API가 있으면 기존 소프트웨어 및 하드웨어 신시사이저, 하드웨어 음악 컨트롤러, 조명 시스템 및 MIDI로 제어되는 기타 기계 장치를 사용하는 웹 애플리케이션을 가능하게 한다. 이 API는 이러한 다양한 사용 사례를 염두에 두고 정의되었다.
이 API가 취한 접근 방식은 Apple의 CoreMIDI API 및 Microsoft의 Windows MIDI API에서 취한 방식과 유사하다. 즉, 이 API는 개발자가 그 위에 강력한 MIDI 소프트웨어를 만들 수 있도록 MIDI의 저수준 소프트웨어 프로토콜을 나타내도록 설계되었다. 이 API는 개발자가 입력 및 출력 인터페이스를 열거하고 MIDI 메시지를 보내고 받을 수 있게 하지만, (앞서 언급한 API들과 유사하게) 현재 장치를 견고하게 지원하는 데 필요한 범위를 넘어 MIDI 메시지를 의미론적으로 정의하거나 해석하려고 시도하지 않는다.
Web MIDI API는 시퀀싱 같은 고수준 개념을 직접 구현하려는 것이 아니다. 예를 들어 Standard MIDI Files를 직접 지원하지는 않지만, Standard MIDI File 플레이어는 Web MIDI API 위에 구축할 수 있다. 또한 General MIDI가 하는 것처럼 패치나 컨트롤러 할당을 의미론적으로 포착하려는 것도 아니다. 그러한 해석은 Web MIDI API의 범위를 벗어난다(하지만 다시 말해, General MIDI는 Web MIDI API를 통해 쉽게 활용할 수 있다).
비규범적으로 표시된 절뿐만 아니라, 이 명세의 모든 작성 지침, 다이어그램, 예제 및 참고는 비규범적이다. 이 명세의 그 밖의 모든 것은 규범적이다.
이 문서의 핵심 단어 MUST 및 SHOULD는 여기에 표시된 것처럼 모두 대문자로 나타나는 경우에만, BCP 14 [RFC2119] [RFC8174]에 설명된 대로 해석되어야 한다.
이 명세는 단일 제품에 적용되는 준수 기준을 정의한다. 그 제품은 이 명세에 포함된 인터페이스를 구현하는 사용자 에이전트이다.
ECMAScript를 사용하여 이 명세에서 정의한 API를 구현하는 구현은 Web IDL 명세 [WEBIDL]에 정의된 ECMAScript 바인딩과 일관된 방식으로 이를 구현해야 한다. 이 명세는 해당 명세와 용어를 사용하기 때문이다.
Web Audio API와 그 관련 인터페이스 및 개념은 [webaudio]에서 정의된다.
용어 MIDI, MIDI 장치, MIDI 입력 포트, MIDI 출력 포트, MIDI 인터페이스, MIDI 메시지, System Real Time 및 System Exclusive는 [MIDI]에서 정의된다.
8, 9,
A, B 또는 E이면 전체 메시지 길이는 3
바이트여야 한다
C 또는 D이면
전체 메시지 길이는 2바이트여야 한다F1 또는 F3이면 전체 메시지
길이는 2바이트여야 한다F2이면 전체 메시지 길이는
3바이트여야 한다F6, F8, FA, FB,
FC, FE
또는 FF이면 전체 메시지 길이는 1바이트(상태
바이트만)여야 한다
F0이면 이는 길이 제한이 없는
System
Exclusive 메시지이며, 마지막
바이트는 F7이어야 한다
F4, F5, F7, F9 또는
FD이면
그 메시지는 유효하지 않다
Web Midi API는 강력한 기능이며, 이름 "midi"로 식별된다. 이는 다음 권한 관련 플래그를 정의함으로써 Permissions와 통합된다.
WebIDLdictionary MidiPermissionDescriptor : PermissionDescriptor {
boolean sysex = false;
};
{name: "midi", sysex: true}는 {name:
"midi", sysex: false}보다 더 강하다.
Web Midi API는
"midi"라는 정책 제어
기능을 정의하며, 이는 'self'의
기본
허용 목록을 가진다.
WebIDL[SecureContext, Exposed=(Window,Worker)] interface MIDIInputMap {
readonly maplike <DOMString, MIDIInput>;
};
MIDIInputMap은 값이
MIDIInput 인스턴스이고 키가 그 ID인
maplike 인터페이스이다.
이 타입은 현재 사용 가능한 모든 MIDI 입력 포트를 나타내는 데 사용된다.
WebIDL[SecureContext, Exposed=(Window,Worker)] interface MIDIOutputMap {
readonly maplike <DOMString, MIDIOutput>;
};
MIDIOutputMap은 값이
MIDIOutput 인스턴스이고 키가 그 ID인
maplike 인터페이스이다.
이 타입은 현재 사용 가능한 모든 MIDI 출력 포트를 나타내는 데 사용된다.
이 인터페이스는 MIDI 입력 및 출력 장치를 나열하고, 개별 장치에 대한 접근을 얻기 위한 메서드를 제공한다.
WebIDL[SecureContext, Exposed=(Window,Worker), Transferable] interface MIDIAccess: EventTarget {
readonly attribute MIDIInputMap inputs;
readonly attribute MIDIOutputMap outputs;
attribute EventHandler onstatechange;
readonly attribute boolean sysexEnabled;
};
inputs
outputs
onstatechange
새 포트가 연결되거나 기존 포트가 state 속성을 변경할 때 호출되는 핸들러.
MIDIConnectionEvent 타입인 이
이벤트
핸들러는 MIDIAccess
인터페이스를 구현하는 모든 객체에서 지원되어야 한다.
이 객체에 EventHandler를
연결된 채로 두면 이 객체가 가비지 컬렉션되는 것을
막는다는 점을 이해하는 것이 중요하다. MIDIAccess 사용을
마쳤으면 모든 onstatechange 리스너를 제거해야 한다.
이전에는 사용할 수 없었던 MIDI 포트를 사용할 수 있게 되거나, 기존 포트가 state 속성을 변경할 때마다, 사용자 에이전트는 다음 단계를 실행해야 한다.
MIDIPort로 둔다.
MIDIAccess에서 "statechange"라는 이름으로 발생시키고,
MIDIConnectionEvent를 사용하며, port는 port로 설정한다.
sysexEnabled
이 인터페이스는 MIDI 입력 또는 출력 포트를 나타낸다.
WebIDL[SecureContext, Exposed=(Window,Worker)] interface MIDIPort: EventTarget {
readonly attribute DOMString id;
readonly attribute DOMString? manufacturer;
readonly attribute DOMString? name;
readonly attribute MIDIPortType type;
readonly attribute DOMString? version;
readonly attribute MIDIPortDeviceState state;
readonly attribute MIDIPortConnectionState connection;
attribute EventHandler onstatechange;
Promise <MIDIPort> open();
Promise <MIDIPort> close();
};
id
포트의 고유 ID. 개발자는 이를 사용하여 사용자가
애플리케이션에서 선택한 포트를 기억할 수 있다.
사용자 에이전트는 id가 오직
해당 포트에 대해서만 고유하도록 보장해야 한다.
사용자 에이전트는 이 id가 애플리케이션 인스턴스 사이에서
유지되도록 보장해야 한다. 예를 들어 시스템이
재부팅될 때와 장치가 시스템에서 제거될 때도 유지되어야 한다.
애플리케이션은 MIDI 설정을 다시 만들기 위해 이러한 id를
로컬에 캐시하기를 원할 수 있다. 일부 시스템은 완전히 고유한
지속 식별자를 지원하지 않을 수 있다. 그런 경우에는 다른
인터페이스가 시스템에 추가되거나 제거될 때 식별자를 유지하기가
더 어려워진다. (이는 요청된 포트의 인덱스를 어긋나게 할 수 있다.)
시스템은 MIDI API의 인스턴스 사이에서 포트를 일치시키기 위해
최선을 다할 것으로 예상된다. 예를 들어 구현은 포트 인터페이스의
제조사, 이름 및 인덱스에 대한 어떤 형태의 해시를 불투명하게
id로 사용할 수 있으며, 그러면 그 포트 id에 대한 참조가
연결되었을 때 해당 포트와 일치할 가능성이 높다.
애플리케이션은 MIDIPort의 id 비교를 사용하여 동등성을
테스트할 수 있다.
manufacturer
포트의 제조사.
name
포트의 시스템 이름.
type
포트가 입력 포트인지 출력 포트인지 구별하기 위한
설명자 속성. MIDIOutput의 경우 이는
"output"이어야 한다. MIDIInput의 경우 이는
"input"이어야 한다.
version
포트의 버전.
state
connection
onstatechange
기존 포트가 state 또는 connection 속성을 변경할 때 호출되는 핸들러.
"statechange" 타입인 이 이벤트
핸들러는 MIDIPort 인터페이스를
구현하는 모든 객체에서 지원되어야 한다.
이 객체에 EventHandler를
연결된 채로 두면 이 객체가 가비지 컬렉션되는 것을
막는다는 점을 이해하는 것이 중요하다. MIDIPort 사용을
마쳤으면 모든 onstatechange 리스너를 제거해야 한다.
open
MIDIPort에 해당하는
MIDI 장치를
명시적으로 사용할 수 있게 한다. 이 호출은
MIDIPort를 사용하는 데
필요하지 않다는 점에 유의한다. MIDIOutput에서
send()를 호출하거나,
MIDIInput에 MIDIMessageEvent EventHandler를
연결하거나,
MIDIInput에 MIDIMessageEvent EventListener를
추가하면 암시적 open()이 발생한다. 기반
구현은 이 호출에 응답하여 아무것도 할 필요가 없을 수도 있다.
그러나 일부 기반 구현은 MIDI 장치에 대한
공유 접근을 지원하지 못할 수 있으므로, 명시적
open() 및 close() 호출을 사용하면 MIDI 애플리케이션이
장치에 대한 이러한 독점 접근을 예측 가능하게 제어할 수 있다.
호출되면, 이 메서드는 사용자의 시스템에 있는 주어진 MIDI 포트에 대한 접근 요청을 나타내는 Promise 객체를 반환한다.
포트 장치의 상태가 "connected"인 경우, 포트에 대한 접근이 얻어지면(그리고 포트가 입력 또는 출력을 위해 준비되면), 제공된 Promise는 이행된다.
연결된 포트에 대한 접근을 사용할 수 없는 경우(예를 들어 포트가 독점 접근 전용 플랫폼에서 이미 사용 중인 경우), Promise는 거부된다.
open()이 "disconnected"인 포트에서
호출되면, 포트의 .connection은
포트가 "connected"가 되거나 그에 대한 모든 참조가
제거될 때까지 "pending"으로 전환된다.
제공된 Promise가 모두 settled되지 않았더라도
open()을 여러 번 호출하는 것이 허용된다.
이 메서드가 호출되면, 사용자 에이전트는 MIDIPort를 여는 알고리즘을 실행해야 한다.
promise를 새 Promise 객체로, resolver를 그 관련 resolver로 둔다.
promise를 반환하고 다음 단계를 비동기적으로 실행한다.
port를 주어진 MIDIPort 객체로 둔다.
장치의 연결이 이미 "open"이면
(예: 이 MIDIPort에서 open()이
이미 호출되었거나 포트가 암시적으로 열렸다면), 아래
success로 표시된 단계로 이동한다.
장치의 연결이 "pending"이면 (즉, 연결이 열렸고 이후 장치가 연결 해제되었다면), 아래 success로 표시된 단계로 이동한다.
장치의 상태가 "disconnected"이면,
MIDIPort의
connection 속성을
"pending"으로 변경하고,
새 MIDIConnectionEvent를
MIDIAccess의
statechange 핸들러와
MIDIPort의
statechange 핸들러에 큐에 넣고,
아래 success로 표시된 단계로 이동한다.
시스템에서 주어진 MIDI 장치에 대한 접근을 얻으려고 시도한다. 장치를 사용할 수 없으면 (예: 다른 프로세스에서 이미 사용 중이어서 열 수 없거나, 연결 해제되었으면) 아래 failure로 표시된 단계로 이동한다. 장치를 사용할 수 있고 접근을 얻으면, 다음 단계를 계속한다.
MIDIPort의 connection 속성을 "open"으로
변경하고, 새 MIDIConnectionEvent를
MIDIAccess의
statechange 핸들러와
MIDIPort의
statechange 핸들러에 큐에 넣는다.
이 포트가 출력 포트이고 미래의 타임스탬프를 가진 큐에 들어간 전송 데이터가 있으면, 그 데이터를 비동기적으로 보내기 시작한다.
success: resolver의
accept(value) 메서드를 port를
value 인자로 하여 호출한다.
이 단계를 종료한다.
failure: error를 새
DOMException으로
둔다.
포트를 사용할 수 없으면 이 예외의 .name은
"InvalidAccessError"여야 한다.
resolver의 reject(value) 메서드를
error를 value 인자로 하여 호출한다.
close
MIDIPort에 해당하는
MIDI 장치를
명시적으로 사용할 수 없게 한다(이후 상태를 "open"에서
"closed"로 변경한다). 이 메서드의 호출이 성공하면
MIDIInput의 MIDIMessageEvent 핸들러로
MIDI 메시지가 더 이상
전달되지 않는다는 점에 유의한다(다만 새 핸들러를 설정하면
암시적 open()이 발생한다).
기반 구현은 이 호출에 응답하여 아무것도 할 필요가 없을 수도 있다. 그러나 일부 기반 구현은 MIDI 장치에 대한 공유 접근을 지원하지 못할 수 있으며, 명시적 close() 호출은 MIDI 애플리케이션이 다른 애플리케이션이 장치에 접근할 수 있도록 보장하게 한다.
호출되면, 이 메서드는 사용자의 시스템에 있는 주어진 MIDI 포트에 대한 접근 요청을 나타내는 Promise 객체를 반환한다. 포트가 닫히면(따라서 독점 접근 시스템에서는 포트를 다른 애플리케이션이 사용할 수 있게 되면), 제공된 Promise는 이행된다. 포트가 연결 해제되어 있으면 Promise는 거부된다.
제공된 Promise가 모두 settled되지 않았더라도
close()를 여러 번 호출하는 것이 허용된다.
close() 메서드가 호출되면, 사용자 에이전트는
다음 단계를 실행해야 한다.
promise를 새 Promise 객체로, resolver를 그 관련 resolver로 둔다.
promise를 반환하고 다음 단계를 비동기적으로 실행한다.
port를 주어진 MIDIPort 객체로 둔다.
포트가 이미 닫혀 있다면(그 .connection이 "closed"이면 — 예를 들어
포트가 아직 암시적으로 또는 명시적으로 열리지 않았거나,
이 MIDIPort에서
close()가
이미 호출되었다면), 아래 closed로 표시된 단계로 이동한다.
포트가 입력 포트이면 다음 단계로 건너뛴다. 출력 포트의 .state가 "connected"가 아니거나 그 .connection이 "pending"이면, 큐에 들어간 모든 전송 데이터를 지우고 다음 단계로 건너뛴다. 시스템에서 미래의 타임스탬프를 가진 큐에 들어간 전송 데이터를 모두 지운 다음, 다음 단계로 진행하기 전에 타임스탬프가 없거나 과거 또는 현재의 타임스탬프를 가진 모든 전송 메시지의 전송을 완료한다.
열려 있다면 기반 시스템에서 포트에 대한 접근을 닫고, 기반 시스템의 모든 블로킹 리소스를 해제한다.
MIDIPort의 connection 속성을 "closed"로
변경하고, 새 MIDIConnectionEvent를
MIDIAccess의
statechange 핸들러와
MIDIPort의
statechange 핸들러에 큐에 넣는다.
closed: resolver의
accept(value) 메서드를 port를
value 인자로 하여 호출한다.
MIDIPort에
해당하는 MIDI 포트가 state 속성을 변경할 때마다, 사용자 에이전트는
다음 단계를 실행해야 한다.
port를 MIDIPort로 둔다.
이벤트를 발생시키되,
MIDIPort에서
statechange라는 이름으로,
MIDIAccess에서
statechange라는 이름으로
발생시키며, MIDIConnectionEvent를 사용하고,
port 속성은
port로 설정한다.
WebIDL[SecureContext, Exposed=(Window,Worker)] interface MIDIInput: MIDIPort {
attribute EventHandler onmidimessage;
};
onmidimessage
"midimessage" 타입인 이 이벤트
핸들러는 MIDIInput 인터페이스를
구현하는 모든 객체에서 지원되어야 한다.
핸들러가 설정되어 있고 state 속성이 "opened"가 아니면,
기반 구현은 포트를 사용할 수 있게 하려고 시도하고,
state 속성을 "opened"로 변경한다. 성공하면
MIDIConnectionEvent가
해당 MIDIPort와
MIDIAccess에 전달된다.
MIDIInput에 해당하는 MIDI 포트가
하나 이상의 MIDI 메시지 수신을 마칠 때마다,
사용자 에이전트는 다음 단계를 실행해야 한다.
port를 MIDIInput으로 둔다.
MIDIAccess가
System Exclusive
접근을 활성화하지 않았고, 메시지가 System Exclusive 메시지이면,
이 과정을 중단한다.
port에서 "midimessage"라는 이름으로
이벤트를
발생시키되,
MIDIMessageEvent를 사용하고,
timeStamp
속성은 시스템이 메시지를 수신한 시간으로 설정하며,
data 속성은 단일
MIDI
메시지를 나타내는 MIDI 데이터 바이트의
Uint8Array로 설정한다.
MIDI System Real Time 메시지는 실제로 입력 스트림에서 다른 메시지의 중간에 발생할 수 있다는 점을 특별히 언급한다. 이 경우 System Real Time 메시지는 발생하는 대로 디스패치되는 반면, 일반 메시지는 완성될 때까지 버퍼링된 후 디스패치된다.
WebIDL[SecureContext, Exposed=(Window,Worker)] interface MIDIOutput : MIDIPort {
undefined send(sequence<octet> data, optional DOMHighResTimeStamp timestamp = 0);
undefined clear();
};
send
해당 MIDI 포트로 보낼 메시지를 큐에 넣는다.
기반 구현은 (필요한 경우) 시퀀스의 각 멤버를
부호 없는 8비트 정수로 강제 변환한다. Uint8Array가 아니라
sequence를 사용하면 개발자가 Uint8Array를 만들어야 하는
대신, 예를 들어 output.send( new Uint8Array( [ 0x90, 0x45, 0x7f ] )
);가 아니라
output.send( [ 0x90, 0x45, 0x7f ]
);라는 편의성을 사용할 수 있다.
데이터는 하나 이상의 완전한 유효한 MIDI 메시지를 포함한다. 기반 시스템이 이를 지원하지 않을 수 있으므로, 실행 상태는 데이터에서 허용되지 않는다.
data가 유효한 시퀀스가 아니거나
유효한 MIDI 메시지를 포함하지 않으면,
TypeError 예외를 던진다.
data가 System Exclusive 메시지이고,
MIDIAccess가
System Exclusive 접근을 활성화하지 않았다면,
InvalidAccessError 예외를 던진다.
포트가 "disconnected"이면,
InvalidStateError 예외를 던진다.
포트가 "connected"이지만 연결이 "closed"이면, 비동기적으로 포트를 열려고 시도한다.
DOMHighResTimeStamp,
즉 문서의 navigation start를 기준으로 측정한
밀리초 수). timestamp가 0(또는 과거의 다른 시간)으로
설정되면, 데이터는 가능한 한 빨리 전송되어야 한다.
같은 타임스탬프로 send()를 여러 번 호출하면
호출된 순서대로 데이터가 전송되어야 한다.
clear
MIDIOutput의 큐에서 아직 전송되지 않은
큐에 들어간 모든 전송 데이터를 지운다. 구현은 MIDI 스트림이
양호한 상태로 남도록 보장해야 하므로, 출력 포트가 sysex
메시지의 중간에 있다면 sysex 종료 바이트(0xf7)를 보내야 한다.
WebIDLenum MIDIPortType {
"input",
"output",
};
input
MIDIPort가 입력 포트이면, type 멤버는
이 값이어야 한다.
output
MIDIPort가 출력 포트이면, type 멤버는
이 값이어야 한다.
WebIDLenum MIDIPortDeviceState {
"disconnected",
"connected",
};
disconnected
MIDIPort가 나타내는 장치는
시스템에서 연결 해제되어 있다. 장치가 시스템에서 연결 해제되면,
해당 입력 및 출력 포트 맵에 나타나지 않아야 한다.
connected
MIDIPort가 나타내는 장치는
연결되어 있으며, 입력 및 출력 포트 맵에 나타나야 한다.
WebIDLenum MIDIPortConnectionState {
"open",
"closed",
"pending",
};
open
MIDIPort가 나타내는 장치는
(암시적으로 또는 명시적으로) 열렸으며
사용 가능하다.
closed
MIDIPort가 나타내는 장치는
열리지 않았거나 명시적으로 닫혔다. MIDIPort가
명시적으로(MIDIPort.open()를 통해) 또는
암시적으로(입력 포트에 midimessage
이벤트 핸들러를 추가하거나 출력 포트에서 MIDIOutput.send()를
호출함으로써) 열리기 전까지, 이것은 장치의 기본 상태여야 한다.
pending
MIDIPort가 나타내는 장치는
(암시적으로 또는
명시적으로) 열렸지만, 그 뒤 장치가 연결 해제되어
사용할 수 없다. 장치가 다시 연결되면,
statechange
이벤트를 보내기 전에 시스템은 장치를 다시 열려고 시도해야 한다
(MIDIPort를 여는 알고리즘을 따른다). 이로 인해
연결 상태는 "open" 또는 "closed"로 전환된다.
이 인터페이스를 구현하는 이벤트 객체는
MIDI 메시지가 수신될 때
MIDIInput의 onmidimessage 핸들러로
전달된다. DOM Event timeStamp
속성은 DOMHighResTimeStamp로
정의되며, 이벤트가 수신되었거나 전송될 고해상도 시간을
나타낸다는 점에 유의한다.
WebIDL[SecureContext, Exposed=(Window,Worker)]
interface MIDIMessageEvent : Event {
constructor(DOMString type, optional MIDIMessageEventInit eventInitDict = {});
readonly attribute Uint8Array? data;
};
data
단일 MIDI 메시지의 MIDI 데이터 바이트를 포함하는 Uint8Array.
WebIDLdictionary MIDIMessageEventInit: EventInit {
Uint8Array data;
};
data
단일 MIDI 메시지의 MIDI 데이터 바이트를 포함하는 Uint8Array.
이 인터페이스를 구현하는 이벤트 객체는 새 포트를 사용할 수 있게 될 때
(예를 들어 MIDI 장치가 처음
컴퓨터에 연결될 때), 이전에 사용할 수 있었던 포트를 사용할 수
없게 되거나 다시 사용할 수 있게 될 때(예를 들어
MIDI 인터페이스가
연결 해제된 뒤 다시 연결될 때),
MIDIAccess의
onstatechange 핸들러로
전달되며,
(존재하는 경우) 해당 포트를 참조하는 모든
MIDIPort의
onstatechange 핸들러에도 전달된다.
MIDIPort가
"pending" 상태이고 장치가
호스트 시스템에 다시 연결되면, statechange
이벤트를 발생시키기 전에
해당 포트에서 MIDIPort를 여는 알고리즘을 실행하여 포트를 다시 열려고 시도한다.
이 전환이 실패하면(예: 포트가 기반 시스템에서 다른 것에 의해
예약되어 있어 사용할 수 없는 경우) 연결 상태는 "closed"로 이동하고,
그렇지 않으면 다시 "open"으로 전환된다. 이는 장치 상태 변경에 대한
statechange
이벤트 전에 수행되므로, 이벤트가 장치 상태뿐만 아니라 최종 연결 상태도
반영하게 된다.
일부 기반 시스템은 장치 연결 상태에 대한 알림 이벤트를 제공하지 않을 수 있다. 그러한 시스템은 새 장치를 드물게 폴링하므로 긴 시간 지연이 있을 수 있다. 따라서 연결 이벤트에 과도하게 의존하지 않는 것이 좋다.
WebIDL[SecureContext, Exposed=(Window,Worker)]
interface MIDIConnectionEvent : Event {
constructor(DOMString type, optional MIDIConnectionEventInit eventInitDict = {});
readonly attribute MIDIPort? port;
};
port
연결되었거나 연결 해제된 포트.
WebIDLdictionary MIDIConnectionEventInit: EventInit {
MIDIPort port;
};
port
연결되었거나 연결 해제된 포트.
사용자의 MIDI 인터페이스를 열거하도록 허용하는 것은 fingerprinting의 잠재적 대상이다. 즉, 사용자가 연결한 특정 MIDI 인터페이스로 사용자를 고유하게 식별하는 것이다.
이 문맥에서 열거될 수 있는 것은 MIDI 인터페이스라는 점에 유의한다. 여기에는 USB로 호스트 컴퓨터에 연결된 대부분의 장치가 포함된다. USB-MIDI 장치는 일반적으로 자체 MIDI 인터페이스를 가지므로 열거된다. 5핀 DIN 케이블로 MIDI 인터페이스에 연결된 개별 샘플러 또는 신시사이저 MIDI 장치는 열거되지 않는다. fingerprinting될 수 있는 인터페이스는 MIDI "포트"와 동등하며, 각 MIDI 인터페이스에 대해 API는 장치의 이름, 제조사 및 MIDI 인터페이스의 불투명 식별자를 노출한다.
대부분의 시스템에는 연결된 MIDI 인터페이스가 없다. 많은 수의 MIDI 인터페이스가 연결된 시스템은 드물다. 따라서 MIDI 장치 열거로 인한 추가적인 fingerprinting 노출은 Gamepad API가 게임패드 열거를 통해 갖는 추가적인 fingerprinting 노출과 유사하다. 일반적인 사용자는 많아야 몇 개의 장치만 연결하고, 그 구성은 바뀔 수 있으며, 노출되는 정보는 인터페이스 자체에 관한 것이다(즉, 사용자가 구성한 데이터는 아니다).
최초의 MIDI 장치는 웹 플랫폼과 그 보안 위험이 존재하기 전인 1983년에 출시되었다. 많은 MIDI 장치는 제조사가 지원을 중단한 지 오래된 후에도 여전히 사용되고 있다. MIDI는 FireWire, USB, Bluetooth와 같이 원래의 직렬 연결을 넘어서는 전송 방식에도 적응해 왔다. 이는 보안상의 문제를 제기한다. 공식 지원은 없지만 여전히 활발히 사용되고 있으며, 설계자들이 예상하지 못한 방식으로 컴퓨터와 웹에 연결되는, 서로 다른 시대의 장치들이 길게 이어져 있기 때문이다.
우려되는 이론적 공격 중 하나는 USB-MIDI 장치에 대한 악성 펌웨어 업데이트와 관련된다. 일반적으로 USB 장치는 USB 장치 자체에서 전송되는 장치 설명자에 기반하여 동작할 수 있다. USB-MIDI 장치의 펌웨어가 전송되는 설명자를 수정할 수 있다면, 스스로를 인간 인터페이스 장치처럼 동작하게 만들 수 있다. 이는 악성 웹 사이트가 호스트 컴퓨터에서 키 입력이나 다른 이벤트를 읽거나 주입할 수 있게 하며, 시스템 전체의 손상으로 이어질 수 있다.
공격은 다음과 같이 진행된다.
위 공격을 가능하게 하려면 MIDI 장치에 다음 조건이 모두 참이어야 한다.
악성 펌웨어 업데이트에는 취약하지만 다른 조건을 만족하지 않는 MIDI 장치는 이 공격을 통해 호스트 시스템을 손상시키는 데 사용할 수 없다. 악성 펌웨어 업데이트는 여전히 이러한 MIDI 장치가 작동을 멈추거나 원하지 않는 방식으로 동작하게 할 수 있다.
이 위험을 완화하기 위해 구현자는 구현에서 다음 사항을 강조해야 한다.
requestMIDIAccess()를
구현한다.
알려진 MIDI 장치의 허용 목록 또는 차단 목록을 명시적으로 사용하는 것도 이 특정 공격을 완화하는 데 도움이 될 수 있다. 그러나 많은 소규모 회사와 개인이 MIDI 장치를 만들고, 많은 MIDI 장치가 더 이상 지원되지 않으므로, 이렇게 하면 Web MIDI API의 사용성이 크게 낮아질 것이다.
사용할 수 있는 포트를 식별하는 fingerprinting 우려와는 별개로, MIDI 메시지를 보내고 받는 것과 관련된 우려가 있다. 이러한 문제는 아래에서 더 깊이 살펴본다.
MIDI 메시지는 System Exclusive 메시지와 짧은(비-System Exclusive) 메시지로 나눌 수 있다. System Exclusive 메시지는 일반적으로 알려진 MIDI Time Code 및 MIDI Sample Dump Standard 같은 Universal System Exclusive 메시지와, 다른 장치에는 적용되지 않는 “Roland Jupiter-80 신시사이저용 패치 제어 데이터” 같은 장치별 메시지로 다시 나눌 수 있다.
보안 우려를 논의하기 전에, 이러한 기능을 사용하는 MIDI가 어떤 시나리오를 가능하게 하는지 살펴보는 것이 유용하다.
이들 각각의 잠재적 보안 영향은 다음과 같다.
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in:
Referenced in: