2015-06-03 15 views
11

ich durch dieses tolle Artikel arbeiten: https://jackschaedler.github.io/circles-sines-signals/dft_introduction.htmlbenutzerdefinierte Wellenformen in Web Audio API

Ich möchte diese Demo der Web Audio API PeriodicWave Objekt verwenden, zu implementieren: enter image description here

Allerdings, wenn ich eine Set periodische Welle mit diesen Einstellungen:

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

I-Ausgang eine Welle, die wie folgt aussieht:

enter image description here Hier ist der vollständige Code: http://jsbin.com/zaqojavixo/4/edit Um die Wellenform zu sehen, drücken Sie bitte einige Male den Sound.

Ich glaube, diese zusammenpassen sollten, so sind hier meine Fragen:

  1. Bin ich etwas Grundlegendes über die Theorie fehlt hier oder bin ich einfach nicht richtig implementieren? Soll das PeriodicWave-Objekt dasselbe tun wie im Artikel dargestellt?
  2. Wenn ich den falschen Ansatz nehme, wie würde ich dieses Diagramm in Web Audio API implementieren? Ich konnte unten anpassen, indem ich zwei verschiedene Sinuswellen unterschiedlicher Frequenzen mit dem gleichen Verstärkungsknoten verbinde - wie unterscheidet sich das von der Verwendung des PeriodicWave-Objekts?
  3. Ich bin neu in DSP und Web Audio API - jede vorgeschlagene Lesung wäre willkommen!
  4. Zweitens, in meinem Beispiel, muss ich den "play the sound" Knopf ein paar Mal drücken, bevor korrekte Daten auf die Leinwand gezeichnet werden - der Analysator scheint sich hinter dem Oszillator zu befinden, obwohl analyser.getFloatTimeDomainData() ist rief ich nach dem Start des Oszillators irgendwelche Gedanken darüber auf, was hier vor sich geht?

Edit: Wie in den Kommentaren erwähnt, mein Diagramm ist auf dem Kopf (auf der Leinwand 0,0 ist die obere linke Ecke).

Antwort

9

anzumerken, dass die erste Anordnung die Cosinusterme definiert, die zweite ist die sinus terms:

Die real Parameter repräsentiert ein Array von Kosinus Termen (traditionell die A-Bedingungen). In der Audio-Terminologie ist das erste Element (Index 0) der DC-Offset der periodischen Wellenform. Das zweite Element (Index 1) repräsentiert die Grundfrequenz. Das dritte Element repräsentiert den ersten Oberton und so weiter. Das erste Element wird ignoriert und Implementierungen müssen es intern auf Null setzen.

imag Der Parameter stellt ein Array von sine Bedingungen (traditionell die B-Bedingungen). Das erste Element (Index 0) sollte auf Null gesetzt werden (und wird ignoriert), da dieser Begriff in der Fourier-Reihe nicht existiert. Das zweite Element (Index 1) repräsentiert die Grundfrequenz. Das dritte Element repräsentiert den ersten Oberton und so weiter.

Source

Sie werden sehen, Sie die erwartete Wellenform erhalten, aber "umgekehrt" (den Kopf dank gezogen @Julian den Hinweis in seiner Antwort aus - unten festgelegt):

snap

(Ich schrieb hier Ihren Code mit den Arrays ausgetauscht :)
aktualisiert behoben Zeichnung Probleme in Originalcode

//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

Der einzige Unterschied zwischen dem Demo und Ihrer Ausgabe ist die Phasenbeziehung zwischen den beiden Tönen. Die Demo ist y=sin(x) + sin(2x) und Ihre ist y=sin(x) + sin(2x + pi/2). Es ist mir nicht klar, woher diese Phasenverschiebung kommt, aber ich glaube nicht, dass Sie etwas getan haben.

Hier sind einige Plots aus wolfram alpha:

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

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

1

In createPeriodicWave die real Array ist der Cosinus-Teil (oder eine Periode), während die imag Array (die b term) der Sinus Teil ist.

See: http://en.wikipedia.org/wiki/Fourier_series

Ich glaube, Sie haben gerade die beiden invertiert. In dem Artikel heißt es:

Wo Ai die Amplitude des i-ten Sinus ist und fi die Frequenz des der i-te Sinus.

So ist es Ihre imag Array (Sinus-Teil), die [0,0,1,0,1] und Ihre Array sollte [0,0,0,0,0] sein sollte.

So:

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

Versuchen Sie es in Ihrem jsbin du wirst es funktioniert, nur, was es umgekehrt werde, weil Sie in negativ sind Zeichnung (das entspricht 0 Koordinate ist die obere, nicht der Boden). Um zu haben, was in dem Artikel ist, zeichnen Sie entweder umgekehrt oder haben Sie Ihr Imag-Array wie folgt: [0,0, -1,0, -1].

Wenn Sie ein wenig mit verschiedenen imag und real Konfiguration spielen wollen und die Ergebnisse sehen, können Sie hier sehen: http://themusictoolbox.net/waves/

Verwandte Themen