Непонятка с таймером

Дело было вечером, делать было нечего ))))
Вот это вот должно играть “Во саду ли в огороде”. Но почему-то таймер работает не как я ожидаю. Цикл пробегает весь без задержки таймера.
Мне нужно, что бы между buzzer/enable = true и = false была задержка указанной длины:
Получается мелодия то играет, но без задержки. Т.е. у нот нет длительности.

var nC = 261.7;
var nC$ = 277.2;
var nD = 293.7;
var nD$ = 311.1;
var nE = 329.6; 
var nF = 349.2;
var nF$ = 370.0; 
var nG = 392.0; 
var nG$ = 415.3;
var nA = 440.0; 
var nA$ = 466.2;
var nB = 493.9;
var Tempo = 120;
var VoSadu = [nF, 4, nF, 4, nE, 4, nE, 4,
              nE, 4, nE, 4, nE, 4, nF, 4,
              nF, 4, nF, 4, nE, 4, nE, 4,
              nE, 2, nE, 2
             ];

defineVirtualDevice("Music", 
                    {
                      title: "Музыка",
                      cells: {
                        Play: {
                          title: "Играть",
                          type: "pushbutton",
                          value: false,
                        }
                      }
                    }
                   );

function PlayM(nnNote, nnLength){
   var nLen = 4000/nnLength;
   log(CurrentNote, nnNote, nLen);
   dev["buzzer/frequency"] = nnNote;
   dev["buzzer/enabled"] = true;
   setTimeout(function () {
      dev["buzzer/enabled"] = false;
   }, nLen);  
}

defineRule("PlayMusic", {
  whenChanged: "Music/Play",
  then: function (newValue, devName, cellName) {
    log("Pressed. Length = {}",VoSadu.length);
    for(CurrentNote = 0; CurrentNote < VoSadu.length; CurrentNote += 2){
       PlayM(VoSadu[CurrentNote], VoSadu[CurrentNote + 1])
    }
   },
});

Собственно вопрос в том, что я недопонял про таймер и где ошибся?
Мне по сути некий Delay нужен

Выглядит так, будто все ноты (таймеры) включаются одновременно.

я не увидел причин по которым вторая нота начнет воспроизводиться после первой, а не вместе с нею.

Вот я и хотел понять что я не те так с таймером сделал.
Пока заменил на

function sleep(milliseconds) {
  var start = new Date().getTime();
  for (var i = 0; i < 1e7; i++) {
    if ((new Date().getTime() - start) > milliseconds){
      break;
    }
  }
}

По сути, я ожидаю, что это будет работать как delay:

function sleep2(milliseconds) {
  setTimeout(function(){
        log("I am setTimeout");
  },milliseconds); //delay is in milliseconds
}

Но при вызове sleep2 задержки не происходит. В логе сначала вываливаются все ноты скопом, а после все “I am setTimeout” так же скопом. Получается таймер асинхронный. Он просто выполняет то, что внутри через нужное время, не прерывая ход программы. Теперь становится понятно.

Добрый день!
Сразу скажу — что-то внятное «сыграть» на встроенном бузере, к сожалению, не получится.
Тоже в своё время пытался воспроизвести имперский марш, но в итоге пришёл к выводу, что лучше подключить внешнюю звуковую карту и нормальные колонки на случай ЧП.

У вас получилось так, что потоки частот идут параллельно и не формируют нормальную мелодию.
Чтобы всё звучало более правильно, нужно:

  • отключать бузер после каждой ноты,
  • переключать частоту,
  • и только потом включать звук для новой ноты.

Примерно так это должно выглядеть для корректного воспроизведения мелодии.

// Определение частот нот
var nC = 261.7;
var nC$ = 277.2;
var nD = 293.7;
var nD$ = 311.1;
var nE = 329.6; 
var nF = 349.2;
var nF$ = 370.0; 
var nG = 392.0; 
var nG$ = 415.3;
var nA = 440.0; 
var nA$ = 466.2;
var nB = 493.9;

// Темп (не используется напрямую, но может быть полезен для расчётов позже)
var Tempo = 120;

// Массив мелодии: нота, длительность (4 = четверть ноты, 2 = половинная и т.п.)
var VoSadu = [
  nF, 4, nF, 4, nE, 4, nE, 4,
  nE, 4, nE, 4, nE, 4, nF, 4,
  nF, 4, nF, 4, nE, 4, nE, 4,
  nE, 2, nE, 2
];

// Создание виртуального устройства с кнопкой "Играть"
defineVirtualDevice("Music", {
  title: "Музыка",
  cells: {
    Play: {
      title: "Играть",
      type: "pushbutton",
      value: false,
    }
  }
});

// Правило воспроизведения мелодии
defineRule("PlayMusic", {
  whenChanged: "Music/Play",
  then: function (newValue, devName, cellName) {
    log("Pressed. Length = {}", VoSadu.length);
    var i = 0; // Индекс текущей ноты в массиве

    function playNextNote() {
      if (i >= VoSadu.length) {
        log("Finished playing melody");
        return; // Все ноты сыграны
      }

      var note = VoSadu[i];
      var duration = VoSadu[i + 1];
      var noteLength = 4000 / duration; // Вычисляем длительность ноты в миллисекундах

      log("Playing note", note, "for", noteLength, "ms");

      dev["buzzer/frequency"] = note;
      dev["buzzer/enabled"] = true;

      setTimeout(function () {
        dev["buzzer/enabled"] = false;

        // Пауза перед следующей нотой (можно изменить при необходимости)
        var pauseBetweenNotes = 50; // 50 мс

        i += 2; // Переходим к следующей паре нота-длительность
        setTimeout(playNextNote, pauseBetweenNotes);
      }, noteLength);
    }

    playNextNote(); // Запускаем первую ноту
  }
});

Это управление самогонным аппаратом. Колонки это излишество. А музыка это just for fun.
Спасибо за разъяснения и пример.

1 лайк

Добрый день!
Да, для самогонника колонки — точно излишне. Хотя в конце проиграть мелодию победы из Марио было бы действительно весело!

Остались ли ещё вопросы?

Вроде бы нет. Дальше допилю. Спасибо.

1 лайк