Javascript: ожидание ответа от устройства MIDI перед продолжением l oop в асинхронной связи - PullRequest
0 голосов
/ 20 апреля 2020

Я использую протокол MIDI с веб-интерфейсом MIDI API для связи с MIDI Decive. Я хочу отправлять MIDI-сообщения на это устройство каждый раз, ожидая ответа или тайм-аута для отправки следующего сообщения. ответ получен через.

Я хочу следующее:

//gotMIDImessage will be called when the message is received
midiIn.onmidimessage = gotMIDImessage;
function gotMIDImessage(messageData) {
  //Do something with the data
}
//send bunch of messages in a loop and wait for responce each time
function askDevice(){
  for (var i=0;i<n;i++){
    for (var j=0;j<m;j++){
      midiOut.send([0xF0,0x52,0x00,0x61,0x09,0x00,i,j,0xF7]);
      //wait for gotMIDImessage or timeout to continue and do something about the response hre
    }
  }
}

Это моя первая попытка:

midiIn.onmidimessage = gotMIDImessage;

function gotMIDImessage(messageData) {
  received.innerHTML=received.innerHTML+"<br>"+messageData.data;
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(1);
    }, 100);
  });
}


async function askDevice() {
  var o = {'data': 'await'};
  for (var i=0;i<5;i++){
    for (var j=0;j<3;j++){
      var res=await gotMIDImessage(o);
      midiOut.send([0xF0,0x52,0x00,0x61,0x09,0x00,i,j,0xF7]);
    }
  }
}

Очевидно, что это не работает, потому что await gotMIDImessage(); вызывает функцию gotMIDImessage(), но эта функция срабатывает автоматически при получении сообщения.

Как мне это сделать?

РЕДАКТИРОВАТЬ: я пробовал также эту версию, которая, кажется, не работает

received=null;
midiMessage=null;
function gotMIDImessage(messageData) {
  received=true;
  midiMessage=messageData.data;
}

function sendWait(message){
  received=false;
  midiOut.send(message);
  function waitForIt(){
    if(!received){
      setTimeout(function(){waitForIt()},1000);
    }else{
      alert("received");
    }
  } 
  return midiMessage;
}
function askDevice() {
  var o = {'data': 'await'};
  for (var i=0;i<5;i++){
    for (var j=0;j<3;j++){
      res=sendWait([0xF0,0x52,0x00,0x61,0x09,0x00,i,j,0xF7]);
    }
  }
}

res всегда равен нулю, и я получаю все 15 сообщений после завершения l oop

1 Ответ

0 голосов
/ 20 апреля 2020

Вы можете сделать это так:

function awaitReply(msg, timeout = 5000) {
  return new Promise((resolve, reject) => {
    const gotMidiMessage = msg => {
      midiIn.removeEventListener('midimessage', gotMidiMessage); // Removing the event listener again
      resolve(msg);
    };
    midiIn.addEventListener('midimessage', gotMidiMessage);
    midiOut.send(msg);
    setTimeout(() => {
      // Don't forget to remove the event listener
      midiIn.removeEventListener('midimessage', gotMidiMessage);
      /* Resolve the Promise anyway ... */
      resolve(null);
      /* ... OR reject it, but then you have to catch the error in the call */
      // reject('Error message');
    }, timeout);
  });
}

async function askDevice() {
  for (let i = 0; i < 5 ; i++) {
    for (let j = 0; j < 3; j++) {
      let res = await awaitReply([0xF0, 0x52, 0x00, 0x61, 0x09, 0x00, i, j, 0xF7]);
    }
  }
}

Вот рабочий пример:

function awaitReply(msg) {
  return new Promise(resolve => {
    const gotMidiMessage = messageData => {
      window.removeEventListener('midimessage', gotMidiMessage); // Removing the event listener again
      resolve(messageData);
    };
    window.addEventListener('midimessage', gotMidiMessage);
    midiOut.send(msg);
  });
}

async function askDevice() {
  for (let i = 0; i < 5 ; i++) {
    for (let j = 0; j < 3; j++) {
      let res = await awaitReply([0xF0, 0x52, 0x00, 0x61, 0x09, 0x00, i, j, 0xF7]);
      // Logging your iterator variable which you want to send
      console.log(res.detail[6], res.detail[7]);
    }
  }
}

const midiOut = {
  send(msg) {
    return setTimeout(() => {
      let evt = new CustomEvent('midimessage', { detail: msg });
      window.dispatchEvent(evt);
    }, 1000);
  }
};

askDevice();
...