0

我创建了代码来使用网络音频 api 生成莫尔斯电码声音。摩尔斯电码声音工作完美。我想用那个声音来闪烁屏幕的一部分。只有两个声音点(。)和破折号(-)。我想通过闪烁屏幕的一部分来显示消息。 我尝试将 div 的背景颜色设置为黑色,然后隐藏/显示该 div 以提供闪光效果。但它没有按预期工作。请帮助我....提前谢谢...我试过这个:

$(document).ready(function() {
	var context = new (window.AudioContext || window.webkitAudioContext());
	var O= new MorseNode(context,20);
	O.connect(context.destination);
	O.playString(1,'.-- -..');

});

function MorseNode(ac, rate) {
    // ac is an audio context.
    this._oscillator = ac.createOscillator();
    this._gain = ac.createGain();

    this._gain.gain.value = 0;
    this._oscillator.frequency.value = 550;

    this._oscillator.connect(this._gain);

    if(rate == undefined)
        rate = 20;
    this._dot = 1.2 / rate; // formula from Wikipedia.

    this._oscillator.start(0);
}

MorseNode.prototype.connect = function(target) {
    return this._gain.connect(target);
}

MorseNode.prototype.playChar = function(t, c) {
    for(var i = 0; i < c.length; i++) {
        switch(c[i]) {
        case '.':
            $('#flashBlock').hide(); //I tried this to flash the screen.
            this._gain.gain.setValueAtTime(1.0, t);
            t += this._dot;
            this._gain.gain.setValueAtTime(0.0, t);
            $('#flashBlock').show();
            break;
        case '-':
            $('#flashBlock').hide();
            this._gain.gain.setValueAtTime(1.0, t);
            t += 3 * this._dot;
            this._gain.gain.setValueAtTime(0.0, t);
            $('#flashBlock').show();
            break;          
        }
        t += this._dot;
    }
    return t;
}

MorseNode.prototype.playString = function(t, w) {
    w = w.toUpperCase();
    for(var i = 0; i < w.length; i++) {
        if(w[i] == ' ') {
            t += 3 * this._dot; // 3 dots from before, three here, and
                                // 1 from the ending letter before.
        }
        else if(w[i] != undefined) {
            t = this.playChar(t, w[i]);
            t += 2 * this._dot;
        }
    }
    return t;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<html>
   <div id="flashBlock" style="Background:black;display:none;height:100px;width:100px">
		</div>
</html>

4

1 回答 1

0

问题是您正在执行元素操作的地方将在音频上下文播放声音之前运行。setValueAtTime()设置一个事件,在这种情况下是增益变化,在特定时间发生。您的隐藏/显示调用不会与这些事件设置同步,因为它们会立即运行,因此它们会在音频之前运行。

您还遇到了另一个问题,hide()几乎show()是紧跟其后,这将基本上相互抵消。在调用其他方法之前需要经过一定的时间才能正确渲染动画。

您需要做的是设置一个计时系统以在正确的时间执行隐藏/显示。

一种方法是创建一个数组,其中包含详细说明何时开始和结束隐藏/显示操作的对象。

var flashBlock = $('#flashBlock'); //cache this so you dont create it each time

//in constructor
this.flashTimes = [];

//in playChar()
this.flashTimes.push({
  timestamp:t,
  end:t+this._dot // or t+(3*this._dot)
});

然后不断检查音频流以检查它的时间,如果它在正确的时间开始操作。

MorseNode.prototype.flashLoop = function(){
  var ct = ac.currentTime;
  var currentFlash = this.flashTimes[0];
  if(ct >= currentFlash.timestamp && ct < currentFlash.end){
     // remove it from the queued
     this.flashTimes.shift(); 
     // determine how much time the animation can 
     // last between now and when it is supposed to end.
     let duration = ac.currentTime - currentFlash.end;

     // first argument to hide / show is duration of animation,
     // the second is a callback to be called when animation is done
     flashBlock.hide(duration-100,()=>{
       flashBlock.show(100);
     });
  }
  requestAnimationFrame(()=>this.flashLoop());
}

requestAnimationFrame(()=>this.flashLoop());

var flashBlock = null;
$(document).ready(function() {
  flashBlock = $('#flashBlock');
  var context = new(window.AudioContext || window.webkitAudioContext());
  var O = new MorseNode(context, 20);
  O.connect(context.destination);
  O.playString(1, '.-- -.. ... - . --- .-. --.');
});

function MorseNode(ac, rate) {
  this.flashTimes = [];
  this.ac = ac;
  
  // ac is an audio context.
  this._oscillator = ac.createOscillator();
  this._gain = ac.createGain();

  this._gain.gain.value = 0;
  this._oscillator.frequency.value = 550;

  this._oscillator.connect(this._gain);

  if (rate == undefined)
    rate = 20;
  this._dot = 1.2 / rate; // formula from Wikipedia.

  this._oscillator.start(0);
}

MorseNode.prototype.connect = function(target) {
  return this._gain.connect(target);
}

MorseNode.prototype.playChar = function(t, c) {
  switch (c) {
    case '.':
      this.flashTimes.push({
        timestamp: t,
        end: t + this._dot
      });
      this._gain.gain.setValueAtTime(1.0, t);
      t += this._dot;
      this._gain.gain.setValueAtTime(0.0, t);
      break;
    case '-':
      this.flashTimes.push({
        timestamp: t,
        end: t + (3 * this._dot)
      });
      this._gain.gain.setValueAtTime(1.0, t);
      t += 3 * this._dot;
      this._gain.gain.setValueAtTime(0.0, t);
      break;
  }
  t += this._dot;

  return t;
}

MorseNode.prototype.playString = function(t, w) {
  w = w.toUpperCase();
  for (var i = 0; i < w.length; i++) {
    if (w[i] == ' ') {
      t += 3 * this._dot;
    } else if (w[i] != undefined) {
      t = this.playChar(t, w[i]);
      t += 2 * this._dot;
    }
  }
  requestAnimationFrame(() => this.flashLoop());
  return t;
}

MorseNode.prototype.flashLoop = function() {
  var ct = this.ac.currentTime;
  var currentFlash = this.flashTimes[0];
  if (!currentFlash) return;

  if (ct >= currentFlash.timestamp && ct < currentFlash.end) {
    this.flashTimes.shift(); // remove it from the queued actions
    let duration = this.ac.currentTime - currentFlash.end;
    flashBlock.hide(duration - 100, () => {
      flashBlock.show(100);
    });
  }
  requestAnimationFrame(() => this.flashLoop());
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<html>
<div id="flashBlock" style="Background:black;display:none;height:100px;width:100px">
</div>

</html>

于 2017-09-01T20:18:05.430 回答