• Das Erstellen neuer Accounts wurde ausgesetzt. Bei berechtigtem Interesse bitte Kontaktaufnahme über die üblichen Wege. Beste Grüße der Admin

Web Audio Analyser analysiert nicht.

husst schrieb:
ich bin hier raus
ja sorry aber irgend wann werde ich auch mal cholerisch, da ich es einfach nicht verstehen kann das du den link nicht ausprobieren möchtest.
Dann hättet du im ersten Beitrag schon erkannt das es bis zu Tonausgabe einwandfrei funktioniert.

Ich hatte Wahnsinnigen hunger las uns wider versöhnen.


Du muss aber auch verstehen das ich fast ein Jahr gebraucht habe um einen vernünftigen "sample rate-, samplrate anpassungs" Algorithmus zu Programmierern oder eher zu Entwickeln.
Da erkläre ich nicht alles bis ins Detail, bzw. Posaune ich nicht alles raus.
Am Ende sind andere menschen schneller als ich klauen mir meine Idee un dich habe nix davon und 2 Jahre an Freizeit verschwendet.

Las es uns noch noch mal einen neuen Punk an setzten.
Also bis zu Tonausgabe geht alles einwandfrei.
vielleicht kann man den Anlayser gar nicht direkt mit den SP verbinden, am ende ist das gar nicht vorgesehen
 
ja sorry aber irgend wann werde ich auch mal cholerisch, da ich es einfach nicht verstehen kann das du den link nicht ausprobieren möchtest.
warum sollte ich?

Dann hättet du im ersten Beitrag schon erkannt das es bis zu Tonausgabe einwandfrei funktioniert.
das ist mir erst mal egal

Ich hatte Wahnsinnigen hunger las uns wider versöhnen.
wir müssen uns nicht versöhnen, wenn ich das persöhnlich nehmen würde, würde ich nicht in einem forum unterwegs sein.
aber wenn du deinen code nicht erklären willst, kann ich dir nicht helfen

Du muss aber auch verstehen das ich fast ein Jahr gebraucht habe um einen vernünftigen "sample rate-, samplrate anpassungs" Algorithmus zu Programmierern oder eher zu Entwickeln.
mag sein, soweit ich das jetzt sehe kann er so nicht funktionieren.

Da erkläre ich nicht alles bis ins Detail, bzw. Posaune ich nicht alles raus.
ok

Am Ende sind andere menschen schneller als ich klauen mir meine Idee un dich habe nix davon und 2 Jahre an Freizeit verschwendet.
du willst damit geld machen? hmm, mag sein

Also bis zu Tonausgabe geht alles einwandfrei.
das ist mir egal

vielleicht kann man den Anlayser gar nicht direkt mit den SP verbinden, am ende ist das gar nicht vorgesehen
würde mich wundern
ich bleibe dabei, die stelle ist mindestens problematisch, wenn nicht die ursache
und das ist keine interpolation was du da machst
 
hesst schrieb:
wir müssen uns nicht versöhnen, wenn ich das persöhnlich nehmen würde, würde ich nicht in einem forum unterwegs sein.
Pu da bin ich ja beruhigt, habe mich eben bei dir im Profil ausgekotzt :p

hesst schrieb:
warum sollte ich?
kkapsner sagt immer "schick doch mal ein link" das habe ich gemacht. Damit es eben besser nachzuvollziehen geht. Siehst ja selber das das Skript angeblich nicht funktioniert wenn du kein "working example " siehst.

hesst schrieb:
und das ist keine interpolation was du da machst
Abgeleitet habe ich den ganzen Algorithmus von einen einen uralten issue auf Github, als es noch die Audio Data Api von Mozilla gab. Da ging es eben darum die Daten die von der Audio Data Api kommen mit der Web audio API zu verbinden, da nur die Web audio API FFt und Filtern konnte. Das Ergebnis war eben diese komische Interpolation, ich habe halt noch statt der Audio Data API ein websockt als Quelle.
mann sollte vielleicht SampleRate Anpassung sagen. Aber warum sollte das kein Interpolation sein? seit halt komisch aus da der Sp nur durch die eingestellte anzahl von Samples fährt, vielleicht ist auch auch ein lineare Approximation aber eigentlich nee. Aber auf jede Fall wir irgendwie interpoliert, da mein Chrome eine Rate von 192000Hz hat -Nyquist sin das 96000Hz die ich "hören" kann. Wenn ich jetzt SpecrumlLab zünde und da 192000 Samples einstelle und auch ein FFT Spektrum erstelle was so breit ist dann ist bei 96000Hz Schluss, der Rest der Daten ist nur noch murks. Ergo Interpolation oder was anderes:d


hesst schrieb:
du willst damit geld machen?
Mit diesem QRSS Viewer nicht. Habe mir schon Gedanken gemacht wie man das mit einen ogg Stream bewerkstelligen könnte, da ändert sich nämlich die Pufferung und decodeAudiData erwartet immer EOF, man müsste also eine Umweg über ein BLOB machen. Dann könnte das auch MeidaBroadcast mäßig interessant werden und löst den den dämlichen icecast mp3/httpHeader und Flash Player scheiß ab.

Youtube rendert z.b seine Videos komplett in einen canvas... wen man es den eingestellt hat.

hesst schrieb:
ich bleibe dabei, die stelle ist mindestens problematisch, wenn nicht die ursache
Hm dann muss wohl der ober Guru kkapsner mal hier drüber schauen, oder ich hole die fft Daten von audiolib.js, was aber wider an der Performance nagt.

Edit: leider ist gerade der Server am Anderen ende gestorben so das der link zwar funktioniert aber kein stream mehr ankommt... ich fahre jetzt kein 10km mehr um den server zu reseten. ...Morgen sehe nach liegt bestimmt an no-ip
 
Zuletzt bearbeitet:
kkapsner sagt immer "schick doch mal ein link" das habe ich gemacht.
ich nicht, die menschen sind verschieden
Damit es eben besser nachzuvollziehen geht.
da bin ich anderer meinung, das kann man bei einfachen problemen machen.
ich hab schon viel code gesehen der im debugger entwickelt wurde...

Siehst ja selber das das Skript angeblich nicht funktioniert wenn du kein "working example " siehst.
ich sehe, dass ich erst mal verstehen muss, was du wie erreichen willst

Aber auf jede Fall wir irgendwie interpoliert, da mein Chrome eine Rate von 192000Hz hat -Nyquist sin das 96000Hz die ich "hören" kann. Wenn ich jetzt SpecrumlLab zünde und da 192000 Samples einstelle und auch ein FFT Spektrum erstelle was so breit ist dann ist bei 96000Hz Schluss, der Rest der Daten ist nur noch murks. Ergo Interpolation oder was anderes:d
mal ganz ganz grob gerundet: du hast 2 werte pro sekunde als eingang und brauchst 4 als ausgang. soweit überhaupt richtig?
eingang
|
|
| x
|
| x
|
------>t
dann musst du als ausgang 2 zusätzlich berechnen.
|
|
| x
| o
| x
|o
------>t
soweit überhaupt richtig?
als einfachste lösung legst du zw. beide punkte eine lineare/quadratische/... kurve und berechnest die neuen werte
meist berücksichtigt man noch die stetige differenzierbarkeit in den geg. punkten, sprich es darf keine knicke im verlauf 2er kurven im gemeinsamen stützpunkt geben
 
hesst schrieb:
mal ganz ganz grob gerundet: du hast 2 werte pro sekunde als eingang und brauchst 4 als ausgang. soweit überhaupt richtig?
eingang
|
|
| x
|
| x
|
------>t
dann musst du als ausgang 2 zusätzlich berechnen.
|
|
| x
| o
| x
|o
------>t
soweit überhaupt richtig?
als einfachste lösung legst du zw. beide punkte eine lineare/quadratische/... kurve und berechnest die neuen werte
Das wäre dann eine lineare Interpolation. Dann bräuchte ich wider ein Tiefpass (Anti-Aliasing)... ergo mehr Bearbeitungszeit ergo nicht gut bei Telegrafie.

für mich als "Straßenprogrammierer" sieht dies ziele:
sample = (this.ratioWeight * sample + (ratio - this.ratioWeight) * firstSample) / ratio;
aus wie eine Interpolation. Das ratio gibt den Faktor an es gibt 2 werte aus dem array sample und firstSample und halt das ratioweight.
vielleicht ist es eine "arbitrary interpolation".
kann das issue nicht mehr wiederfinden ist auch schon ein paar Jahre her.

morgen hole ich mal ein 2ten SP ran mal sehn ob der Analyser dann will wenn nicht wird audiolib.js genommen

nicht das es wider Meinungsverschiedenheiten gibt.
das:
sample = (this.ratioWeight * sample + (ratio - this.ratioWeight) * firstSample) / ratio;
ist die nur ein teil der Interpolation vielleicht steigungsgleichung ...irgendwas...

*nachti :sleeping:
 
Zuletzt bearbeitet:
Das wäre dann eine lineare Interpolation. Dann bräuchte ich wider ein Tiefpass (Anti-Aliasing)... ergo mehr Bearbeitungszeit ergo nicht gut bei Telegrafie.
wenn, dann ist deine methode linear(Interpolation lass ich bewusst weg).

morgen hole ich mal ein 2ten SP ran mal sehn ob der Analyser dann will wenn nicht wird audiolib.js genommen
mit audiolib ging es schon mal?
das problem meiner meinung nach ist immer noch, daß du werte weglässt
mal davon ab, dass ich die rechnung mit dem pbs faktor nicht verstehe, damit verfälschst du ja die werte

nicht das es wider Meinungsverschiedenheiten gibt.
das:
sample = (this.ratioWeight * sample + (ratio - this.ratioWeight) * firstSample) / ratio;
ist die nur ein teil der Interpolation
mehr sehe ich nicht

vielleicht steigungsgleichung ...irgendwas...
dreisatz

- - - Aktualisiert - - -

das problem meiner meinung nach ist immer noch, daß du werte weglässt
ist auch so, wenn du alle werte angibst funktioniert es
 
Also das mit den 2 Scriprocessoren funktioniert nicht einer von beiden stop immer den onaudioprocess event oder friert glich ein.

hesst schrieb:
das problem meiner meinung nach ist immer noch, daß du werte weglässt
Jetzt wo du es sagst. Da hatte ich was vergessen.

Hier noch mal die überarbeite Version, nur die for Schleife.
Code:
for (ev=0; ev < Len; ev++) {
               var firstSample = this.FloatBuffer[this.r_ptr];
		//Interpolation Sampleratio berechnen 
                var ratio = this.pBs * this.InRate / this.OutRate;
                this.ratioWeight  += ratio;   
                if(1 <= this.ratioWeight) {
                    this.ratioWeight -= 1; 
                    this.FloatBuffer[this.r_ptr] = 0;
                    this.r_ptr+=1;
                    if (this.bufferSize <= this.r_ptr)this.r_ptr -= this.bufferSize ;
                    var sample = this.FloatBuffer[this.r_ptr];
                    //do Interpolartion
                    sample = (this.ratioWeight * sample + (ratio - this.ratioWeight) * firstSample) / ratio;
                }
		if (sample < -1) sample = -1;
		if (sample > 1) sample = -1;
                if (typeof sample == "undefined") {
                    outputLeft[ev] = firstSample;
                }else{
                     outputLeft[ev] = sample;
                     //console.log(sample, firstSample);
                }
wenn sample undefiniert ist wird firstsample gespielt ansonsten das interpolierte sample.

hesst schrieb:
mal davon ab, dass ich die rechnung mit dem pbs faktor nicht verstehe, damit verfälschst du ja die werte
Der bps Faktor eigentlich ppm(parts per Million) gibt an wie sehr der onmessege event zeitlich gesehen von den Scriprocessor Event abweicht.
Die Berechnung findet auch bei Soundkarten Treibern statt die eingangs rate kann vom adc kann mµ Hz von dac abweichen.
Führer hatten die adc eine rate von 44100 hz der dac eine rate von z.b 96000hz so konnte man rational interpolieren. Mittlerweile muss man da sehr fein Interpolieren.



Die Berechnung dafür ist gar nicht sooo schwer.
var jit = (that.bufferSize * 2 + that.w_ptr - that.r_ptr - (that.audioctx.currentTime - that.SPTime) * that.InRate / 1E3) % that.bufferSize;
Diese ziele ist einheitlich selbst erklären so rechnen wie da steht. 1E3 = 1000, da audioctx.currentTime ja ms sind und that.InRate 22050Hz sind, Hz = sec.
w_prt und r_ptr sind die beiden Zeiger.


hesst schrieb:
ist auch so, wenn du alle werte angibst funktioniert es
nein selbst wenn ich ein weiße rauschen berechne ist das Spektrum schwarz.

Ich poste den code gleich noch mal... dauert paar min muss noch mal wech... der weiße rauch code ist auf nem stick den ich beim kumplel liegen gelassen habe

- - - Aktualisiert - - -

So jetzt noch mal der vereinfachte Code:
Code:
<!DOCTYPE html>

<head>
    <title>Playing sound with WebAudio API</title>
    <script src="lib/audiolib.js"></script>
    <script type="text/javascript" src="chroma.js"></script>    
     <script>
        function start(){
            new player();
        }
	       
	function player(){
           //anaylser/canvas stuff
            this.canvas = document.getElementById("Normal_CW_Window");
            this.canvas_width = this.canvas.width;
            this.canvas_height = this.canvas.height;
            this.canvas_ctx = this.canvas.getContext("2d");
            
            this.tempCanvas = document.createElement("canvas");
            this.tempCtx = this.tempCanvas.getContext("2d");
            this.tempCanvas.width = this.canvas_width;
            this.tempCanvas.height = this.canvas_height;
            
            //chromajs 
            this.colors = new chroma.ColorScale({
            colors: ['#000000', '#0C3AC6', '#ffff00', '#ffffff'],
            positions: [0, .25, .75, 1],
            mode: 'rgb',
            limits: [0, 300]
            });
            
            //Audio Stuff
            this.audioctx = new AudioContext();
	    this.N_of_samples = 1024;
	    this.connection();
	}
        
        player.prototype.connection =function(){
            var Processor = this.audioctx.createScriptProcessor(this.N_of_samples, 0, 1);
            	    
            this.SpectrumAnaylser = this.audioctx.createAnalyser();
            this.SpectrumAnaylser.smoothingTimeConstant = 0;
            this.SpectrumAnaylser.fftSize = 2048;
            this.FFT_Data = new Uint8Array(this.SpectrumAnaylser.frequencyBinCount);
            
                Processor.onaudioprocess = this.play.bind(this);
		Processor.connect(this.audioctx.destination);
                Processor.connect(this.SpectrumAnaylser );
                
        }
	
        player.prototype.play = function(ev){
	    console.log("ss")
            var outputLeft = ev.outputBuffer.getChannelData(0)
            var Len = ev.outputBuffer.length;           ;
            for (ev=0; ev < Len; ev++) {
               outputLeft[ev] = Math.random()*2-1;
            } //ende for
        }

        player.prototype.drawSpectrogram = function(FFT_Data){
            var drawLength = FFT_Data.length < this.canvas_height ? this.canvas_height : FFT_Data.length;
            this.tempCtx.drawImage(this.canvas, 0, 0, this.canvas_width, this.canvas_height);
            console.log( FFT_Data[4]);
            for (var i = 0; i < drawLength; i++) {
                // draw each pixel with the specific color
                var value = FFT_Data[i];
                this.canvas_ctx.fillStyle = this.colors .getColor(value).hex();
                // draw the line at the right side of the canvas
                this.canvas_ctx.fillRect(this.canvas_width - 1, this.canvas_height - i, 1, 1);
            }
            // set translate on the canvas
            this.canvas_ctx.translate(-1, 0);
            // draw the copied image
            this.canvas_ctx.drawImage(this.tempCanvas, 0, 0, this.canvas_width, this.canvas_height, 0, 0, this.canvas_width, this.canvas_height);
            // reset the transformation matrix
            this.canvas_ctx.setTransform(1, 0, 0, 1, 0, 0);
        }       
    </script>
</head>

<body onload=start();>
    <canvas id="Normal_CW_Window" width="893" height="730" style="display: block; background-color: black ;"></canvas>
</body>
</html>

auch hier passiert nix bzw das:
fft error.png
 
Hallo,
ich habe ein neues Problem und zwar habe ich da es mit den web audio Analyser nicht funktioniert audiolib.js für den fft Vorgang genommen.
Doch die Methode Analyser.prototype.pushSample wird nie ausgelöst. in der Console steht keine Fehlermeldung. Warum?

im Objekt Player ist Analyser.pushSample immer undefined, sagt zumindest das console.log().

Code:
<!DOCTYPE html>

<head>
    <title>Playing sound with WebAudio API</title>
    <script src="lib/audiolib.js"></script>
    <script type="text/javascript" src="chroma.js"></script>
    
     <script>
        function start(){
            new player();
	    new Analyser(4096,30);
        }
        
        function Analyser(fftSize, scrollInteval){
	    var fps = scrollInteval;
	    this.Analyser1 = new audioLib.FFT(44100, fftSize);
	    
	    //anaylser/canvas stuff
            this.canvas = document.getElementById("Normal_CW_Window");
            this.canvas_width = this.canvas.width;
            this.canvas_height = this.canvas.height;
            this.canvas_ctx = this.canvas.getContext("2d");
            
            this.tempCanvas = document.createElement("canvas");
            this.tempCtx = this.tempCanvas.getContext("2d");
            this.tempCanvas.width = this.canvas_width;
            this.tempCanvas.height = this.canvas_height;
	    
	    //chromajs 
            this.colors = new chroma.ColorScale({
            colors: ['#000000', '#0C3AC6', '#ffff00', '#ffffff'],
            positions: [0, .25, .75, 1],
            mode: 'rgb',
            limits: [0, 300]
            });
	    
	    setInterval(this.drawSpectrogram(),1000/fps);
    
	}
        
	Analyser.prototype.pushSample = function(sample){
	  // this.Analyser1.pushSample(sample);
	   console.log(sample)
	}
	
	Analyser.prototype.drawSpectrogram = function(){
	    var FFT_Data =  this.Analyser1.spectrum;
            var drawLength = FFT_Data.length < this.canvas_height ? this.canvas_height : FFT_Data.length;
            this.tempCtx.drawImage(this.canvas, 0, 0, this.canvas_width, this.canvas_height);
             document.getElementById("ausgabe3").innerHTML = "FFT value: "+ FFT_Data[4];
            for (var i = 0; i < drawLength; i++) {
                // draw each pixel with the specific color
                var value = FFT_Data[i];
                this.canvas_ctx.fillStyle = this.colors .getColor(value).hex();
                // draw the line at the right side of the canvas
                this.canvas_ctx.fillRect(this.canvas_width - 1, this.canvas_height - i, 1, 1);
            }
            // set translate on the canvas
            this.canvas_ctx.translate(-1, 0);
            // draw the copied image
            this.canvas_ctx.drawImage(this.tempCanvas, 0, 0, this.canvas_width, this.canvas_height, 0, 0, this.canvas_width, this.canvas_height);
            // reset the transformation matrix
            this.canvas_ctx.setTransform(1, 0, 0, 1, 0, 0);
        }
	
	
	function player(){
            //Audio Stuff
            this.audioctx = new AudioContext();
	    this.w_ptr = 0;
	    this.r_ptr = 30720;
	    this.bufferSize = 32768; 
	    this.FloatBuffer = new Float32Array(this.bufferSize);
	    this.InRate = 22050;//hz
            this.OutRate = this.audioctx.sampleRate;
            this.N_of_samples = 2048;//number of samples where Script Processor play through
            //some varibles for the jitterbuffer
            this.pBs = 0.0;//toggle the playback speed if the buffer underruns or overrun
            this.ratioWeight = 0.0;
            this.SPTime = 0.0;
            this.connection();
            this.getSamples();
	}
        
         player.prototype.connection =function(){
            var Processor = this.audioctx.createScriptProcessor(this.N_of_samples, 0, 1);   
                Processor.onaudioprocess = this.play.bind(this);
		Processor.connect(this.audioctx.destination);
        }
            
        player.prototype.play = function(ev){	
            var outputLeft = ev.outputBuffer.getChannelData(0)
            var Len = ev.outputBuffer.length;           ;
            for (ev=0; ev < Len; ev++) {
               var firstSample = this.FloatBuffer[this.r_ptr];
	       if(isNaN(firstSample) == true){
			firstSample = this.FloatBuffer[this.r_ptr+1];
		    }
		//Interpolation Sampleratio berechnen 
                var ratio = this.pBs * this.InRate / this.OutRate;
                this.ratioWeight  += ratio;   
                if(1 < this.ratioWeight) {
                    this.ratioWeight -= 1; 
                    this.FloatBuffer[this.r_ptr] = 0.0;
                    this.r_ptr++;
                    if (this.bufferSize <= this.r_ptr)this.r_ptr -= this.bufferSize ;
                    var sample = this.FloatBuffer[this.r_ptr];
                    //do Interpolartion
                    sample = (this.ratioWeight * sample + (ratio - this.ratioWeight) * firstSample) / ratio;
                }
		if (sample < -1) sample = -1;
		if (sample > 1) sample = -1;
                if (typeof sample == "undefined") {
                    outputLeft[ev] = firstSample;
                }else{
                     outputLeft[ev] = sample;
		}
		//wird nie ausgelöst
		Analyser.pushSample(outputLeft[ev]);

            } //ende for
            document.getElementById("ausgabe2").innerHTML = "Sample: "+ outputLeft[0];
            this.SPTime = this.audioctx.currentTime//(new Date).getTime();
        }
            
        player.prototype.getSamples = function(){
            var that = this;
           
            var ws = new WebSocket('ws://192.168.2.102:3000');
            ws.binaryType = 'arraybuffer';
            var response_speed = 500;//ms
            ws.onmessage = function(b) {
                var jit = (that.bufferSize * 2 + that.w_ptr -  that.r_ptr - (that.audioctx.currentTime - that.SPTime) * that.InRate / 1E3) % that.bufferSize;
                response_speed += 0.01 * (jit - response_speed);
                if (response_speed > 2E3){
                    that.r_ptr = (that.bufferSize + that.w_ptr - 1E3) % that.bufferSize;
                    document.getElementById("ausgabe").innerHTML = "Output Index korrektur: "+ that.r_ptr;
                    jit = response_speed = 1E3;
                }
                that.pBs = 1 + 1E-5 * (response_speed - 1E3);
                 document.getElementById("ausgabe4").innerHTML = "Ratio anpassung: "+ Math.round(1E6*(that.pBs-1)) +"ppm";
                if (1.002 < that.pBs)that.pBs = 1.002;
                if (0.998 > that.pBs)that.pBs = 0.998;
                var F32 = new Float32Array(b.data),i=0;
                while(i<F32.length) {
                    that.w_ptr++,i++;
                    that.FloatBuffer[that.w_ptr] = F32[i];
                    if(that.bufferSize<=that.w_ptr)that.w_ptr -= that.bufferSize; 
                }
            }
        }
        
        
        
	
    </script>
</head>

<body onload=start();>
    <canvas id="Normal_CW_Window" width="893" height="730" style="display: block; background-color: black ;"></canvas>
    <div id="debug"></div>
    <br>
    <div id="ausgabe"></div>
    <br>
    <div id="ausgabe2"></div>
        <br>
            <div id="ausgabe2a"></div>
        <br>
    <div id="ausgabe3"></div>
    <br>
    <div id="ausgabe4"></div>
    <br>  
</body>
</html>
 
nein selbst wenn ich ein weiße rauschen berechne ist das Spektrum schwarz.
das mag ja sein, aber das ist ein anderes problem, werte kommen erst mal zurück

im Objekt Player ist Analyser.pushSample immer undefined, sagt zumindest das console.log().
pushSample ist ja auch eine funktion der instanz. also
xxx=new Analyser(...);
xxx.pushSample();// ok
Analyser.pushSample(); // nicht ok
 
hesst schrieb:
das mag ja sein, aber das ist ein anderes problem, werte kommen erst mal zurück
Ja, aber nur für 3ms, dann stirbt der Analyser und schreibt entweder nur noch 255 was bei Unit Maximalwert ist oder er schriebt 0.
Das verhalten ist von Browser zu Browser unterschiedlich, FF macht manchmal son Schmierfilm manchmal nur gelb, Chrome ist immer Schwarz werte sind immer 0.
Mir ist das alles zu anfällig mit den Web Audio Analyser, außerdem ist bei einer fft size von 2048 Schluss. für spezielle Sachen brauch man ein fft Puffergröße von 524288.


pushSample ist ja auch eine funktion der instanz. also
xxx=new Analyser(...);
xxx.pushSample();// ok
Analyser.pushSample(); // nicht ok

Ja stimmt das hatte ich vergessen, aber trotzdem get's nicht, da ich die variable SpectrumAnaylser in der Funktion start stehen habe.
der Player kennt dann den SpectrumAnaylser trotzdem nicht. selbst wenn ich die Schließende klammer von start() bis ans ende des codes nehme.
Code:
 function start(){
            
	   var SpectrumAnaylser =  new Analyser(4096,30);
	    new player();
        }
muss ich da was mit .bind() machen oder muss ich den Analyser in den constructor mit einbringen new player(SpectrumAnaylser);
 
Zuletzt bearbeitet:
hesst schrieb:
du bringst vermutlich den browser an die grenze. ruf mal drawSpectrum in einem animationframe auf
vermutlich. Aber was ist ein animationframe??? ist das besser als ein canvas??

xorg1990 schrieb:
der Player kennt dann den SpectrumAnaylser trotzdem nicht. selbst wenn ich die Schließende klammer von start() bis ans ende des codes nehme.
Das Problemchen hat sich erledigt habe noch mal umstrukturiert und nun geht's. außerdem habe ich auf Eclipse gewechselt da mir da Übersicht in Komodo-edit flöten ging
 
Ah ok das sehe ich mir mal an. allerdings geht die FFT von audiolib.js auch bloß nicht, da kommt immer NaN raus.
Echt frustrierend das ganze. Ich mach jetzt erst mal ne Pause.
 
hesst schrieb:
ja, vermutlich weil du werte weglässt, ich poste morgen mal was
Das hatte ich doch gefixt gucke mal bei #27. Vom posten will ich dich nicht abhalten.

Code:
 if (typeof sample == "undefined") {
                    outputLeft[ev] = firstSample;
                }else{
                     outputLeft[ev] = sample;
                     //console.log(sample, firstSample);
                }

Ps: ich würde davon abraten das console.log zu aktivieren, es seiden man hat ein octa-core Recher mit 32gb ram... so wie ich:cool:
 
Zuletzt bearbeitet:
Das hatte ich doch gefixt gucke mal bei #27.
ich dachte das hattest du nur mal zum testen. aber dann immer den firstSample zu nehmen ist ja auch keine lösung.
ich hab gestern abend mal deinen algorithmus im vergleich zu einer interpolation graphisch dargestellt. blau original, grün deine kurve, rot interpoliert
Code:
<?xml version="1.0" encoding="windows-1252" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<svg xmlns="http://www.w3.org/2000/svg" width="1000" height="1000" xmlns:xlink="http://www.w3.org/1999/xlink">
  <title>test</title>
  <g>
    
  </g>
  <script>
    <![CDATA[
      // Screenkoordinaten
      var x0 = 0;
      var xn = 1000;
      var y0 = 1000;
      var yn = 0;
      // Wertebereich
      var X0 = 0.1;
      var Xn = 0.105;
      var Y0 = -1.1;
      var Yn = 1.1;
      
      function toScreen(X, X0, Xn, x0, xn)
      {
        return x0 + (X - X0) / (Xn - X0) * (xn - x0);
      }
      function X2S(X)
      {
        return toScreen(X, X0, Xn, x0, xn);
      }
      function Y2S(Y)
      {
        return toScreen(Y, Y0, Yn, y0, yn);
      }
      var svgroot = document.documentElement;
      
      function drawAxes(c, w)
      {
        var lineX = document.createElementNS("http://www.w3.org/2000/svg", "line");
        lineX.style.fill = "none";
        lineX.style.stroke = c;
        lineX.style.strokeWidth = "" + w + "px";
        lineX.x1.baseVal.value = X2S(0);
        lineX.y1.baseVal.value = Y2S(Y0);
        lineX.x2.baseVal.value = X2S(0);
        lineX.y2.baseVal.value = Y2S(Yn);
        
        svgroot.appendChild(lineX);
        
        var lineY = document.createElementNS("http://www.w3.org/2000/svg", "line");
        lineY.style.fill = "none";
        lineY.style.stroke = c;
        lineY.style.strokeWidth = "" + w + "px";
        lineY.x1.baseVal.value = X2S(X0);
        lineY.y1.baseVal.value = Y2S(0);
        lineY.x2.baseVal.value = X2S(Xn);
        lineY.y2.baseVal.value = Y2S(0);
        
        svgroot.appendChild(lineY);
      }
      function drawBuffer(b, c, w)
      {
        b.length
        
        var path = document.createElementNS("http://www.w3.org/2000/svg", "path");
        segments = path.pathSegList;
        path.style.fill = "none";
        path.style.stroke = c;
        path.style.strokeWidth = "" + w + "px";
        
        segments.appendItem(path.createSVGPathSegMovetoAbs(X2S(0), Y2S(0)));
        for (var x = 0; x < b.length; ++x)
        {
          if (!isNaN(b[x]))
          {
            segments.appendItem(path.createSVGPathSegLinetoAbs(X2S(x/b.length), Y2S(b[x])));
          }
        }
        svgroot.appendChild(path);
      }
    ]]>
  </script>
  <script>
    <![CDATA[
      function calcSplinesParams(b, p0, pn, A, B, C, D)
      {
        var n = b.length - 1;
        function buildLES(b, p0, pn, B, d)
        {
          var n = b.length - 1;
          for (var i = 1; i < n; ++i)
          {
            B[i] = [];
            for (var j = 0; j <= n; ++j)
            {
              switch (j)
              {
              case i - 1:
                B[i][j] = i / b.length - (i - 1) / b.length;
                break;
              case i:
                B[i][j] = 2 * ((i + 1) / b.length - (i - 1) / b.length);
                break;
              case i + 1:
                B[i][j] = (i + 1) / b.length - i / b.length;
                break;
              default:
                B[i][j] = 0;
              }
            }
            d[i] = 3 * ((b[i+1] - b[i]) / ((i + 1) / b.length - i / b.length) - (b[i] - b[i-1]) / (i / b.length - (i - 1) / b.length));
          }
          // 2 Zusatzbedingungen
          B[0] = [];
          B[n] = [];
          for (var j = 0; j <= n; ++j)
          {
            B[0][j] = 0;
            B[n][j] = 0;
          }
          B[0][0] = 2;
          d[0] = p0;
          B[n][n] = 2;
          d[n] = pn;
        }
        function solveLES(A, b)
        {
          // Lösen des lin. Gl. Systems A*x=b nach Gauß
          var n = b.length;
          // Diagonalenfeld normalisieren
          for (var i = 0; i < n; ++i)
          {
            if (A[i][i] == 0) // 0-en in der Diagonale entfernen
            {
              for (var j = i + 1; j < n; ++j)
              {
                if (A[j][i] != 0)
                {
                  for (var k = 0; k < n; k++)
                  {
                    A[i][k] += A[j][k];
                  }
                  b[i] += b[j];
                  break;
                }
              }
            }
            // Diagonalen auf 1 bringen
            var d = A[i][i];
            if (d != 0)
            {
              for (var j = 0; j < n; ++j)
              {
                A[i][j] /= d;
              }
              b[i] /= d;
            }
            // Spalten außerhalb der Diagonalen auf 0 bringen
            for (var j = 0; j < n; ++j)
            {
              if (i != j )
              {
                d = A[j][i];
                for (var k = 0; k < n; ++k)
                {
                  A[j][k] -= d * A[i][k];
                }
                b[j] -= d * b[i];
              }
            }
          }
        }
        var M = [];
        var a = [];
        var be = [];
        var c = [];
        buildLES(b, p0, pn, M, be);
        solveLES(M, be);
        for(var i = 0; i < n; ++i)
        {
          a[i]=(be[i+1] - be[i]) / (3 * ((i + 1) / b.length - (i) / b.length));
          c[i]=(b[i+1] - b[i]) / ((i + 1) / b.length - (i) / b.length) - (be[i+1] + 2 * be[i]) / 3 * ((i + 1) / b.length - (i) / b.length);
        }
        // jetzt haben wir Si(x)=ai(x-xi)^3 + bi(x-xi)^2 + ci(x-xi) + yi
        for(var i = 0; i < n; ++i)
        {
          A[i] = a[i];
          B[i] = be[i] - 3 * a[i] * (i / b.length);
          C[i] = 3 * a[i] * (i / b.length) * (i / b.length) - 2 * be[i] * (i / b.length) + c[i];
          D[i] = -a[i] * (i / b.length) * (i / b.length) * (i / b.length) + be[i] * (i / b.length) * (i / b.length) - c[i] * (i / b.length) + b[i];
        }
        // jetzt haben wir Si(x)=Ai*x^3 + Bi*x^2 + Ci*x + Di
      }
      function calcSplinesParamsForPoints(b, p0, pn, A, B, C, D, n0, nx)
      {
        var P = [];
        var n = 0;
        for (var p = n0; p <= nx; p++)
        {
          if (p >= 0 && p < b.length)
          {
            P[n++] = { 
              x: p / b.length, 
              y: b[p]
            };
          }
        }
        n = P.length - 1;
        function buildLES(P, p0, pn, B, d)
        {
          var n = P.length - 1;
          for (var i = 1; i < n; ++i)
          {
            B[i] = [];
            for (var j = 0; j <= n; ++j)
            {
              switch (j)
              {
              case i - 1:
                B[i][j] = P[i].x - P[i-1].x;
                break;
              case i:
                B[i][j] = 2 * (P[i+1].x - P[i-1].x);
                break;
              case i + 1:
                B[i][j] = P[i+1].x - P[i].x;
                break;
              default:
                B[i][j] = 0;
              }
            }
            d[i] = 3 * ((P[i+1].y - P[i].y) / (P[i+1].x - P[i].x) - (P[i].y - P[i-1].y) / (P[i].x - P[i-1].x));
          }
          // 2 Zusatzbedingungen
          B[0] = [];
          B[n] = [];
          for (var j = 0; j <= n; ++j)
          {
            B[0][j] = 0;
            B[n][j] = 0;
          }
          B[0][0] = 2;
          d[0] = p0;
          B[n][n] = 2;
          d[n] = pn;
        }
        function solveLES(A, b)
        {
          // Lösen des lin. Gl. Systems A*x=b nach Gauß
          var n = b.length;
          // Diagonalenfeld normalisieren
          for (var i = 0; i < n; ++i)
          {
            if (A[i][i] == 0) // 0-en in der Diagonale entfernen
            {
              for (var j = i + 1; j < n; ++j)
              {
                if (A[j][i] != 0)
                {
                  for (var k = 0; k < n; k++)
                  {
                    A[i][k] += A[j][k];
                  }
                  b[i] += b[j];
                  break;
                }
              }
            }
            // Diagonalen auf 1 bringen
            var d = A[i][i];
            if (d != 0)
            {
              for (var j = 0; j < n; ++j)
              {
                A[i][j] /= d;
              }
              b[i] /= d;
            }
            // Spalten außerhalb der Diagonalen auf 0 bringen
            for (var j = 0; j < n; ++j)
            {
              if (i != j )
              {
                d = A[j][i];
                for (var k = 0; k < n; ++k)
                {
                  A[j][k] -= d * A[i][k];
                }
                b[j] -= d * b[i];
              }
            }
          }
        }
        var M = [];
        var a = [];
        var b = [];
        var c = [];
        buildLES(P, p0, pn, M, b);
        solveLES(M, b);
        for(var i = 0; i < n; ++i)
        {
          a[i]=(b[i+1] - b[i]) / (3 * (P[i+1].x - P[i].x));
          c[i]=(P[i+1].y - P[i].y) / (P[i+1].x - P[i].x) - (b[i+1] + 2 * b[i]) / 3 * (P[i+1].x - P[i].x);
        }
        // jetzt haben wir Si(x)=ai(x-xi)^3 + bi(x-xi)^2 + ci(x-xi) + yi
        for(var i = 0; i < n; ++i)
        {
          A[i] = a[i];
          B[i] = b[i] - 3 * a[i] * P[i].x;
          C[i] = 3 * a[i] * P[i].x * P[i].x - 2 * b[i] * P[i].x + c[i];
          D[i] = -a[i] * P[i].x * P[i].x * P[i].x + b[i] * P[i].x * P[i].x - c[i] * P[i].x + P[i].y;
        }
        // jetzt haben wir Si(x)=Ai*x^3 + Bi*x^2 + Ci*x + Di
      }
    ]]>
  </script>
  <script>
    <![CDATA[
      //globals
      var i;
      var inRate = 22050;
      var outRate = 48000;
      var sinusIn = new Float32Array(inRate);
      for (i = 0; i < inRate; ++i)
      {
        sinusIn[i] = Math.random()*2-1;// Math.sin(Math.PI * 2 / inRate * 2 * i);
      }
      var color = ["blue", "green", "red"];
      drawAxes("black", 1);
      drawBuffer(sinusIn, "blue", 1)

      var sinusOut = new Float32Array(outRate);
      for (i = 0; i < outRate; ++i)
      {
        sinusOut[i] = Math.sin(Math.PI * 2 / outRate * 2 * i);
      }
      //drawBuffer(sinusOut, "green", 3)

      // Krümmung (2. Ableitung) am 1. und am letzten Punkt
      var p0 = 1;
      var pn = 0;
      var sinusC2 = new Float32Array(outRate);
      sinusC2[0] = 0; // hier noch den letzten wert aus dem vorherigen durchgang hinzunehmen
      for (i = 1; i < outRate; ++i)
      {
        var A = [];
        var B = [];
        var C = [];
        var D = [];
        var inIdx = (i / outRate) * inRate;
        inIdx = Math.ceil(inIdx);
        if (inIdx > inRate -1)
        {
          break;
        }
        calcSplinesParamsForPoints(sinusIn, p0, pn, A, B, C, D, inIdx - 2, inIdx + 1);
        if (inIdx > 2)
        {
          inIdx = 1;
        }
        else if (inIdx > 1)
        {
          inIdx = 0;
        }
        sinusC2[i] = A[inIdx] * i/outRate * i/outRate * i/outRate + B[inIdx] * i/outRate * i/outRate + C[inIdx] * i/outRate + D[inIdx];
      }
      for (;i < outRate; ++i)
      {
        // entweder werte puffern oder extrapolieren
        sinusC2[i] = 0; 
      }
      drawBuffer(sinusC2, "red", 1);
      
      var outputBuffer = new Float32Array(outRate);
      var Len = outputBuffer.length;
      var r_ptr = 0;
      var ratioWeight = 0;
      var pBs = 1.0021354346;
      for (var ev=0; ev < Len; ev++)
      {
        var firstSample = sinusIn[r_ptr];
		    //Interpolation Sampleratio berechnen 
        var ratio = pBs * inRate / outRate;
        ratioWeight += ratio;   
        if (1 <= ratioWeight)
        {
          ratioWeight -= 1; 
          sinusIn[r_ptr] = 0;
          r_ptr+=1;
          var sample = sinusIn[r_ptr];
          //do Interpolartion
          sample = (ratioWeight * sample + (ratio - ratioWeight) * firstSample) / ratio;
        }
		    if (sample < -1) sample = -1;
		    if (sample > 1) sample = -1;
        outputBuffer[ev] = sample;
      } //ende for
      drawBuffer(outputBuffer, "green", 1);
      
    ]]>
  </script>
</svg>
oben über den Wertebereich X0, Xn, Y0, Yn kannst du zoomen.
ich hab mal das mit den firstSample weggelassen, da es das ergebniss nochmer verfälscht
das interpolieren dauert etwas, aber da ist auch nichts optimiert, sondern es wird ein gleichungssystem 3. grades gelöst, es gibt sicher bessere, optimierte varianten.

allerdings geht die FFT von audiolib.js auch bloß nicht, da kommt immer NaN raus.
warum die nicht geht, keine ahnung, poste mal den code und die audiolib.js
mit der analysernode geht es jedenfalls. die chroma.js die du nutzt muss eine andere sein, da musste ich was anpassen
Code:
<!DOCTYPE html>
<html>
  <head>
    <title>Playing sound with WebAudio API</title>
    <script type="text/javascript" src="chroma.js"></script>    
    <script>
      function start()
      {
        new player();
      }

      function player()
      {
        //anaylser/canvas stuff
        this.canvas = document.getElementById("Normal_CW_Window");
        this.canvas_width = this.canvas.width;
        this.canvas_height = this.canvas.height;
        this.canvas_ctx = this.canvas.getContext("2d");
                
        this.tempCanvas = document.createElement("canvas");
        this.tempCtx = this.tempCanvas.getContext("2d");
        this.tempCanvas.width = this.canvas_width;
        this.tempCanvas.height = this.canvas_height;
                
        //chromajs 
        this.colors = chroma.scale(['#000000', '#0C3AC6', '#ffff00', '#ffffff']).domain([0, 255]);
        //Audio Stuff
        this.audioctx = new AudioContext();
        this.N_of_samples = 1024;
        this.connection();
        this.drawSpectrogram();
      }
      
      player.prototype.connection =function()
      {
        var Processor = this.audioctx.createScriptProcessor(this.N_of_samples, 0, 1);
        	    
        this.SpectrumAnaylser = this.audioctx.createAnalyser();
        this.SpectrumAnaylser.smoothingTimeConstant = 0;
        this.SpectrumAnaylser.fftSize = 2048;
        
        Processor.onaudioprocess = this.play.bind(this);
        Processor.connect(this.audioctx.destination);
        Processor.connect(this.SpectrumAnaylser );
      }

      player.prototype.play = function(ev){
          var outputLeft = ev.outputBuffer.getChannelData(0)
          var Len = ev.outputBuffer.length;
          for (ev=0; ev < Len; ev++) {
             outputLeft[ev] = Math.random()*2-1;
          } //ende for
      }

      player.prototype.drawSpectrogram = function()
      {
        draw = requestAnimationFrame(this.drawSpectrogram.bind(this));
        
        var dataArray = new Uint8Array(this.SpectrumAnaylser.frequencyBinCount);
        this.SpectrumAnaylser.getByteTimeDomainData(dataArray);
    
        var drawLength = dataArray.length < this.canvas_height ? this.canvas_height : dataArray.length;
        this.tempCtx.drawImage(this.canvas, 0, 0, this.canvas_width, this.canvas_height);
        this.canvas_ctx.drawImage(this.tempCanvas, 1, 0, this.canvas_width-1, this.canvas_height, 0, 0, this.canvas_width - 1, this.canvas_height);
        for (var i = 0; i < drawLength; i++)
        {
          // draw each pixel with the specific color
          var value = dataArray[i];
          this.canvas_ctx.fillStyle = this.colors(value).hex();
          // draw the line at the right side of the canvas
          this.canvas_ctx.fillRect(this.canvas_width - 1, this.canvas_height - i, 1, 1);
        }
      };
    </script>
</head>

<body onload=start();>
    <canvas id="Normal_CW_Window" width="893" height="730" style="display: block; background-color: black ;"></canvas>
</body>
</html>
hier mal mit einem AnimationFrame. da wird nicht mehr alles gezeichnet, aber da wird kaum gehen, vielleicht wenn du den scriptnodebuffer größer machst.
 
Zuletzt bearbeitet:
Uuii, das ist aber viel Content.

Habe das Problem inzwischen gefunden.
Und zwar ist an der Stelle:
var firstSample = this.FloatBuffer[this.r_ptr];
der Wert manch mal NaN, warum k.a da ja im FloatArray immer 0 oder Samples drinnen sind.
Hab's mit if(isNaN(firstSample) == true){... gelöst

Auch das Wasserfall rollt:
wasser -gut.png

Eins wundert mich trotzdem noch wenn ich die fft Abtastwerte von 4096 auf 32768Punkte erhöhe wird die Auflösung immer schlechter statt besser.:confused:
Ich rede von der audiolib.js fft .

Dann ist da noch eine Frage ich möchte in das Spectrum "herein zoomen" sprich ich brauche nur ein Spektrum von 5kHz-10kHz auf da ganze canvas wie bekomme ich aus dem FFT Array heraus wo 5-10kHz sind?
Das ist doch bestimmt von der größe des Arrays und des FFT Punktzahl abhängig
 
Dann ist da noch eine Frage ich möchte in das Spectrum "herein zoomen" sprich ich brauche nur ein Spektrum von 5kHz-10kHz auf da ganze canvas wie bekomme ich aus dem FFT Array heraus wo 5-10kHz sind?
die auflösung pro index sollte samplingrate / fftSize sein

- - - Aktualisiert - - -

Eins wundert mich trotzdem noch wenn ich die fft Abtastwerte von 4096 auf 32768Punkte erhöhe wird die Auflösung immer schlechter statt besser.
dein canvas ist 730 pixel groß, du stellst also nur die ersten 730 Frequenzbereiche dar. die liegen bei 32768 werten dichter beisammen
 
Zurück
Oben