Подтвердить что ты не робот

Пользовательские формы волны в API веб-аудио

Я работаю над этой замечательной статьей: https://jackschaedler.github.io/circles-sines-signals/dft_introduction.html

Я хочу использовать объект Web Audio API PeriodicWave для реализации этой демонстрации: enter image description here

Однако, когда я устанавливаю периодическую волну с этими настройками:

 var real = new Float32Array([0,0,1,0,1]);
 var imag = new Float32Array(real.length);
 var customWave = context.createPeriodicWave(real,imag);
 osc.setPeriodicWave(customWave);

Я вывожу волну, которая выглядит так:

enter image description here Вот полный код: http://jsbin.com/zaqojavixo/4/edit Чтобы увидеть форму волны, нажмите несколько раз кнопку воспроизведения.

Я считаю, что они должны совпадать, так что вот мои вопросы:

  • Я пропустил что-то фундаментальное в теории здесь или я просто неправильно его внедряю? Предполагается ли, что объект PeriodicWave выполняет то же самое, что иллюстрируется в статье?
  • Если я ошибаюсь, как бы реализовать эту диаграмму в API веб-аудио? Я смог сопоставить ниже, подключив две разные синусоидальные волны разных частот к одному и тому же коэффициенту усиления node - как это отличается от использования объекта PeriodicWave?
  • Я новичок в DSP и API веб-аудио - любое предлагаемое чтение будет оценено!
  • Во-вторых, в моем примере мне нужно несколько раз нажать кнопку "воспроизвести звук", прежде чем на холст будут нарисованы правильные данные. Анализатор, похоже, находится за осциллятором, хотя analyser.getFloatTimeDomainData() после того, как я запустил осциллятор, какие-то мысли о том, что здесь происходит?

Изменить: Как отмечено в комментариях, мой график перевернут (на холсте 0,0 находится верхний левый угол).

4b9b3361

Ответ 1

Обратите внимание, что первый массив определяет члены косинуса, второй - синусные члены:

Параметр real представляет массив из косинусных терминов (традиционно A). В звуковой терминологии первым элементом (индекс 0) является DC-смещение периодического сигнала. Второй элемент (индекс 1) представляет собой основную частоту. Третий элемент представляет собой первый обертон и т.д. Первый элемент игнорируется и реализации должны установить его на ноль внутри.

Параметр imag представляет массив из синусов (традиционно B). Первый элемент (индекс 0) должен быть установлен на ноль (и будет игнорироваться), так как этот член не существует в рядах Фурье. Второй элемент (индекс 1) представляет основную частоту. третий элемент представляет собой первый обертон и т.д.

Источник

Вы увидите, что вы получили ожидаемую форму волны, но "перевернули" (вверху вниз, благодаря @Julian, указав, что в его ответе - исправлено ниже):

snap

(Я ввел ваш код здесь, когда массивы обменивались:)
обновленная проблема с фиксированным рисунком в исходном коде

//setup audio context
window.AudioContext = window.AudioContext || window.webkitAudioContext;
var context = new window.AudioContext();

//create nodes
var osc; //create in event listener so we can press the button more than once
var masterGain = context.createGain();
var analyser = context.createAnalyser();

//routing
masterGain.connect(analyser);
analyser.connect(context.destination);

var isPlaying = false;

//draw function for canvas
function drawWave(analyser, ctx) {
  
  var buffer = new Float32Array(1024),
      w = ctx.canvas.width;
  
  ctx.strokeStyle = "#777";
  ctx.setTransform(1,0,0,-1,0,100.5); // flip y-axis and translate to center
  ctx.lineWidth = 2;
  
  (function loop() {
    analyser.getFloatTimeDomainData(buffer);
    
    ctx.clearRect(0, -100, w, ctx.canvas.height);

    ctx.beginPath();
    ctx.moveTo(0, buffer[0] * 90);
    for (var x = 2; x < w; x += 2) ctx.lineTo(x, buffer[x] * 90);
    ctx.stroke();
    
    if (isPlaying) requestAnimationFrame(loop)
  })();
}

//button trigger
$(function() {  
  var c = document.getElementById('scope'),
      ctx = c.getContext("2d");
  
  c.height = 200;
  c.width = 600;
  
  // make 0-line permanent as background
  ctx.moveTo(0, 100.5);
  ctx.lineTo(c.width, 100.5);
  ctx.stroke();
  c.style.backgroundImage = "url(" + c.toDataURL() + ")";
  
  $('button').on('mousedown', function() {
    osc = context.createOscillator();
    //osc settings
    osc.frequency.value = 220;
    var imag= new Float32Array([0,0,1,0,1]);   // sine
    var real = new Float32Array(imag.length);  // cos
    var customWave = context.createPeriodicWave(real, imag);  // cos,sine
    osc.setPeriodicWave(customWave);

    osc.connect(masterGain);
    osc.start();
    isPlaying = true;
    
    drawWave(analyser, ctx);
  });

  $('button').on('mouseup', function() {
    isPlaying = false;
    osc.stop();
  }); 
});
button {position:fixed;left:10px;top:10px}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Play the sound</button>
<canvas id='scope'></canvas>

Ответ 2

Единственное различие между демо и вашим выходом - это соотношение фаз между двумя тонами. Демонстрация y=sin(x) + sin(2x), а ваша - y=sin(x) + sin(2x + pi/2). Мне не представляется очевидным, откуда этот фазовый сдвиг, но я не думаю, что это было сделано.

Вот некоторые графики из вольфрама альфа:

y = sin (x) + sin (2x)

y = sin (x) + sin (2x + pi/2)

Ответ 3

В createPeriodicWave массив real является косинусной частью (или термином), в то время как массив imag (b-член) является синусной частью.

Смотрите: http://en.wikipedia.org/wiki/Fourier_series

Я думаю, вы только что перевернули два. В статье говорится:

Где Ai - Амплитуда i-го синуса, а fi - частота i-й синус.

Итак, ваш массив imag (sine part), который должен быть [0,0,1,0,1], и ваш реальный массив должны быть [0,0,0,0,0].

Вот так:

var imag = new Float32Array([0,0,1,0,1]);
 var real = new Float32Array(real.length);

Попробуйте в своем jsbin, вы это сработаете, только это будет инвертировано, потому что вы рисуете отрицательный (значение 0 - верхнее, а не нижнее). Чтобы иметь то, что в статье, либо рисуйте в обратном направлении, либо создайте свой массив изображений следующим образом: [0,0, -1,0, -1].

Если вы хотите немного поиграть с различными настройками imag и real и посмотреть результаты, вы можете увидеть здесь: http://themusictoolbox.net/waves/