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

Audio klingt komisch, Fensterfunktion gehen nicht

Für einen Optimale Darstellung ist ein Überlappung von 50% Scrollinterval und FFT Berechnungszeit notwendig.
hä?

Um auf 19Khz zu kommen brauch ich eine FFT Length von 2048.
Weil, Bin_Breite_in_Hertz = fSample / fft_length = 44100 Hz / 4096 = 10.766 Hz. 2048*10.766 Hz = ca 22050 Hz.
hä?
wenn du 4096 samples eines mit 44100 samples/s abgetasteten signals durch die fft jagst hast du 2048 verschiedene frequenzbänder
die höchste frequenz die du mit 44100 samples/s messen kannst beträgt 22050hz. das aufgeteilt auf 2048 bänder ist ein frequenzbereich von ~11 hz pro band. sammelst du nur 2048 samples ein, hast du immerhin noch ~22 bei 1024 sind es ~43.
und welche auflösung brauchst du jetzt? willst du 11hz von 12 bis 22hz unterscheiden? willst du 43hz von 44 bis 86 unterscheiden?
jetzt kannst du das resamplen auf sagen wir mal 20480 samples/s
damit erhöhst du deine auflösung auf 5 hz bei 4096 und 20 hz bei 1024 sampel ABER alle frequenzen von 10240 bis 22050hz sind weg.
um auf eine 5 hz auflösung bei 44100 samples/s zu kommen müsstest du 8820 samples aufsammeln.
8820 samples hast du nach 0,2s und 4096 nach ~0,09s.
du kannst also einmal 5hz von 5-10hz unterscheiden, aber nur mit einer zeitlichen genauigkeit von 0,2s
oder du kannst 11 hz von 12-22hz unterscheiden, aber die zeitliche reihenfolge der frequenzen innerhalb von 0,09s nicht.

Bei einer rate von 44100 und FFT length von 4096 sind wir als schon mal im richtigen bereich.
Nun der Overlap from scroll intervall:
SecFürNeueDaten = fft_Length * (1/Rate) = 4096*(1/44100) = 0,09287981859410430839002267573696 sec.
Scrollintervall ist auf 40ms gesetzt.
X = 100*40/ (0,09287981859410430839002267573696 *1000)
OSI = 100-x
Die Überlappung beträgt: 56,933%
hä?
das Scrollintervall? du meinst, du hast nen timeout, in dem du zeichnest? was gerade da ist? schlechte idee, 1. bekommst du das nicht synchron und 2. bekommst du kein festes scrollintervall von 40s.
immer wenn die fft durch ist, speicherst du die daten ab und zeichnest die alle im requestAnimationFrame-callback. fertig
die zeit-auflösung der frequenzen sollten ja nicht nach der zeichen-geschwindigkeit gewählt werden, sondern nach der signaldauer.
hat man langsame lange signale, kann man die fft-size erhöhen und hat damit eine schlechte zeitliche aber eine gute auflösung der frequenzbereiche.

- - - Aktualisiert - - -

Wenn ich in der Hann Funktion 0 zuführe kommt auch 0 wider raus, auch der berechnete Sinus klingt fehlerfrei.
Erst wenn ich echte Daten in die Funktion packe kommt wider müll raus.

Ich habe mal was getestet. Habe in der Funktion vor der Berechnung ein console.log gemacht und danach, jeweils nur von ersten SP Aufruf (4096 samples).

Ausgabe vor der berechnung:

Ausgabe nach der Berechnung
o: dein "sinus"
h: was aus deiner funktion kommt
x3.png
mal nur dein ausschnitt der 1. paar samples:
x.png
und das ergebniss deiner funktion vergrößert
x2.png
 
xorg1990 schrieb:
Um auf 19Khz zu kommen brauch ich eine FFT Length von 2048.
Ich meinte natürlich FFT Length von 4096. Heraus kommt ein FFT Array von 2048+1. Im ersten Element ist der DC-Offset. Aber ich wollte nicht so ins Detail gehen.

tsseh schrieb:
ABER alle frequenzen von 10240 bis 22050hz sind weg.
Wenn ich Upsample ist doch nix weg.

tsseh schrieb:
das Scrollintervall? du meinst, du hast nen timeout, in dem du zeichnest? was gerade da ist? schlechte idee, 1. bekommst du das nicht synchron und 2. bekommst du kein festes scrollintervall von 40s.
Es sind 40ms und ja 40ms sind für den Javascrip Timer schon Grenzwertig. Aber für Normal-CW reicht das für QRSS-3 hat man schon 300ms Intervall.
Ja der Interval ist gegeben, eine Feste Konstante so zu sagen. Gegeben ist auch die Frequenz wo sich alles abspielt 12-19khz. Und von diesen 12-19 Khz will sich ein User aber nun auch nur ein teil rauspicken 12-13kHZ mach 1khz diesen bereich möchte er auf einen Canvas darstellen. Es kann aber sein das ein User noch weiter rein zoomt und von den 12-13khz nur 300Hz rauspickt.
Der intervall geht immer egal ob Daten da sind oder nicht.

Das Ganze sieht dann so aus:
https://www.youtube.com/watch?v=aZ75CXTfNko

Um die Zeichnen korrekt erkernen muss man eben Samplen tun und machen.

tsseh schrieb:
immer wenn die fft durch ist, speicherst du die daten ab und zeichnest die alle im requestAnimationFrame-callback. fertig
die zeit-auflösung der frequenzen sollten ja nicht nach der zeichen-geschwindigkeit gewählt werden, sondern nach der signaldauer.
Nein das geht nicht, ich will ja die gesendeten zeichne erkennen (Morse, DFCW, WSPR).


Ps Diese Frequenz von 12-19Khz könnte auch noch runtermischen auf 0-7Khz. Wenn man aber drei mal An den Frequenzen rumspielt weiß man dann gar nicht mehr wo ist nun was.
Hinzukommen noch Spiegelfrequenzen.

o: dein "sinus"
h: was aus deiner funktion kommt

Ei, das schaut aber nicht schön aus. Was läuft schief??
 
Zuletzt bearbeitet:
Ich meinte natürlich FFT Length von 4096. Heraus kommt ein FFT Array von 2048+1. Im ersten Element ist der DC-Offset. Aber ich wollte nicht so ins Detail gehen.
und ich sage, die aussage "Um auf 19Khz zu kommen brauch ich eine FFT Length von" ergibt keinen sinn.
"um bei einem 19kHz signal auf eine auflösung von ??? zu kommen brauch ich eine FFT Length von" müsste das heißen

Wenn ich Upsample ist doch nix weg.
und wo bringt Upsamplen dich weiter? dein signal wird verfälscht, die auflösung wird bei gleicher fft size schlechter.

Ja der Interval ist gegeben, eine Feste Konstante so zu sagen. Gegeben ist auch die Frequenz wo sich alles abspielt 12-19khz.
dein zeichenintervall ist aber nicht von der signalfrequenz abhängig.

Und von diesen 12-19 Khz will sich ein User aber nun auch nur ein teil rauspicken 12-13kHZ mach 1khz diesen bereich möchte er auf einen Canvas darstellen. Es kann aber sein das ein User noch weiter rein zoomt und von den 12-13khz nur 300Hz rauspickt.
auch von der auflösung ist dein zeichenintervall nicht abhängig.

Nein das geht nicht, ich will ja die gesendeten zeichne erkennen (Morse, DFCW, WSPR).
keine ahnung was du erkennen willst, zeichnen willst du ein frequenzspektrum über der zeit wenn ich dich richtig verstanden habe. das kannst du aber in jedem intervall aktualisieren. ist das intervall länger, hast du mehr in jedem intervall zu zeichnen, als in einem kürzeren

Ei, das schaut aber nicht schön aus. Was läuft schief??
da hab ich noch ein problem in der festlegung meines x-wertes
Code:
> m
    x            variable        value
1   1 as.numeric.o.1.10.. 0.000000e+00
[COLOR="#FF0000"]2   3 as.numeric.o.1.10.. 3.200684e-04[/COLOR]
3   4 as.numeric.o.1.10.. 6.393658e-04
4   5 as.numeric.o.1.10.. 9.571229e-04
5   6 as.numeric.o.1.10.. 1.272574e-03
6   7 as.numeric.o.1.10.. 1.584960e-03
7   8 as.numeric.o.1.10.. 1.893527e-03
8   9 as.numeric.o.1.10.. 2.197532e-03
9  10 as.numeric.o.1.10.. 2.496244e-03
[COLOR="#FF0000"]10  2 as.numeric.o.1.10.. 2.788942e-03[/COLOR]
11  1 as.numeric.h.1.10.. 0.000000e+00
12  3 as.numeric.h.1.10.. 4.773635e-12
13  4 as.numeric.h.1.10.. 3.818903e-11
14  5 as.numeric.h.1.10.. 1.288877e-10
15  6 as.numeric.h.1.10.. 3.055106e-10
16  7 as.numeric.h.1.10.. 5.966980e-10
17  8 as.numeric.h.1.10.. 1.031089e-09
18  9 as.numeric.h.1.10.. 1.637321e-09
19 10 as.numeric.h.1.10.. 2.444032e-09
20  2 as.numeric.h.1.10.. 3.479854e-09

- - - Aktualisiert - - -

nu aber
nee, nu aber
Anhang anzeigen x.pdf
passt also
Anhang anzeigen x.pdf
 
Zuletzt bearbeitet:
tsseh schrieb:
keine ahnung was du erkennen willst,
Das ist das Problem, Du hast kein Ahnung was QRSS, Normal-CW, DFCW usw ist und wie man das decodiert. Das geht nur via Auge oder Ohr.



tsseh schrieb:
zeichnen willst du ein frequenzspektrum über der zeit wenn ich dich richtig verstanden habe.
Ja, genaugenommen möchte ich Morse zeichnen in einem Frequenzspektrum darstellen das über eine zeit hinweg läuft!
Der scrollintervall hängt von der zu morsenden Geschwindigkeit ab.


tsseh schrieb:
und wo bringt Upsamplen dich weiter?
Der Resampler verfolgt bloß den zweg, da die Api keinen festgelegte Rate hat. Es ist aber besser wenn ein Eigentümer festlegen kann "die Rate ist es ". Sonst hat ja jeder user eine andre Überlappung vom scrollinterval, Equivalent Noise Bandwidth usw. Außerdem wie soll man das konfigurieren. An Rechner a ist es so, und an Rechner b ist es anders... das geht so nicht.

tsseh schrieb:
Also Sinus ok?

Was ist nun mit den werten?
[-0, 1.8837996440534965e-10, 1.505223501396813e-9, 5.069923147971167e-9, 1.198377574951337e-8, 2.332104642732702e-8, 4.0120180955227625e-8, 6.337516822441103e-8, 9.402719314266506e-8, 1.3295648670919036e-7, 1.8097449583365233e-7, 2.3881648303358816e-7, 3.071344281124766e-7, 3.864903987960133e-7, 4.773503974320192e-7, 5.800785629617167e-7, 6.949322255422885e-7, 8.220573022299504e-7, 9.614840337235364e-7,
 
Das ist das Problem, Du hast kein Ahnung was QRSS, Normal-CW, DFCW usw ist und wie man das decodiert.
ja

Ja, genaugenommen möchte ich Morse zeichnen in einem Frequenzspektrum darstellen das über eine zeit hinweg läuft!
ok, wir kommen der sache näher

Der scrollintervall hängt von der zu morsenden Geschwindigkeit ab.
nein, das zeichenintervall hängt max. von deinem auge ab. und der resampler kontraproduktiv - denke ich

aber ist ja auch erstmal egal.


Also Sinus ok?
Was ist nun mit den werten?
siehe anhang, kommt genau das raus, was du erwartest

- - - Aktualisiert - - -

Der Resampler verfolgt bloß den zweg, da die Api keinen festgelegte Rate hat. Es ist aber besser wenn ein Eigentümer festlegen kann "die Rate ist es ".
genau davon rede ich ja, der Eigentümer hat die rate ja festgelegt. das ist die, die bei dir ankommt. diese jetzt erst für die tonausgabe zu resamplen und das geresamplete signal dann nochmal zu resamplen ist humbug.

Der scrollintervall hängt von der zu morsenden Geschwindigkeit ab.
deine fft hängt von der zu morsenden Geschwindigkeit, der höhe der frequenzänderung und der samplingrate des signals ab.
die fft size muss also eigentlich vom anwender kommen, da nur dieser weiss, was er sucht.
 
nein, das zeichenintervall hängt max. von deinem auge ab.
Falsch, wenn ich ein Fenster hab was 768Pixel lang ist und von rechts nach links rendert, in einem Intervall von 40ms und es wird im QRSS-3 Mode gemorst. Dann ist ein Punkt schon 3 Minuten lang und ein Stich 6 Minuten. Bei ein Intervall von 40ms weiß ich nicht sendet der eine Punkt oder Stich. Also muss ich den Intervall verlangsamen auf was weiß ich 300ms. Zusätlich muss ja ein komplettes Rufzeichen auf das Fenster passen nicht das der erste Buchstabe schon wider links verschwindet.

<- nur mal so als beispiel

die fft size muss also eigentlich vom anwender kommen, da nur dieser weiss, was er sucht.
Kommt sie auch, das stellt er ja alles im Backend ein.

deine fft hängt von der zu morsenden Geschwindigkeit, der höhe der frequenzänderung und der samplingrate des signals ab.
+den Signal Rauschabstand, + der größe des Fensters. Was nützt ein 300Hz Spektrum auf einer länge von 3000Pixeln. Dann ist ein Stich ja Daumen dick, es seiden man erhöht die FFT.


Jedenfalls habe ich noch das Gefühl das was nicht stimmt, ich sehe ja auch was gerendert wird.. nämlich müll.

Ich habe die werte mal beggenzt auf -1 bis +1 via if(s<-1 || s>1)s=1;

Code:
wf.prototype.windowHann = function(sampleBuffer){
	var l = sampleBuffer.length;
	var s = 0;
	var arg = 2.0*Math.PI/(l-1);
	if(this.j++<1){
		console.log(sampleBuffer);
	for(var i=0; i<l;i++){
	 s = sampleBuffer[i] * 0.5-0.5 * Math.cos(arg*i);// nicht 0.5 * (1 - Math.cos(DSP.TWO_PI * index / (length - 1)));
	 if(s<-1 || s>1)s=1;
	 sampleBuffer[i] = s;
	}
	console.log(sampleBuffer);
	this.windowCallback(sampleBuffer);
	}

};
Kommt das bei raus:
Vor der berechnung
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…]
nach der Berechnung:
[-0.5, -0.49999940395355225, -0.49999764561653137, -0.499994695186615, -0.4999905824661255, -0.4999852776527405, -0.49997881054878235, -0.4999711513519287, -0.49996232986450195, -0.4999523162841797, -0.4999411404132843, -0.4999287724494934, -0.4999152421951294, -0.49990054965019226, -0.49988463521003723, -0.49986758828163147, -0.4998493492603302, -0.4998299181461334, -0.4998093247413635, -0.4997875392436981, -0.4997645914554596, -0.49974048137664795, -0.4997151494026184, -0.49968868494033813, -0.49966102838516235, -0.49963217973709106, -0.49960219860076904, -0.4995709955692291, -0.4995386302471161, -0.49950510263442993, -0.49947038292884827, -0.4994345009326935, -0.4993974268436432, -0.4993591904640198, -0.49931979179382324, -0.4992791712284088, -0.49923741817474365, -0.499194473028183, -0.4991503655910492, -0.4991050660610199, -0.4990586042404175, -0.49901095032691956, -0.4989621341228485, -0.49891215562820435, -0.4988609850406647, -0.4988086223602295, -0.4987551271915436, -0.49870043992996216, -0.49864456057548523, -0.4985875189304352, -0.498529314994812, -0.49846991896629333, -0.49840936064720154, -0.4983476400375366, -0.4982847273349762, -0.49822065234184265, -0.498155415058136, -0.4980889856815338, -0.4980213940143585, -0.4979526102542877, -0.4978826642036438, -0.49781155586242676, -0.4977392852306366, -0.4976658225059509, -0.49759119749069214, -0.49751538038253784, -0.4974384009838104, -0.4973602592945099, -0.49728095531463623, -0.49720048904418945, -0.49711883068084717, -0.4970359802246094, -0.49695199728012085, -0.4968668222427368, -0.49678048491477966, -0.4966929852962494, -0.496604323387146, -0.4965144693851471, -0.4964234530925751, -0.49633127450942993, -0.49623793363571167, -0.4961434006690979, -0.4960477352142334, -0.4959508776664734, -0.49585285782814026, -0.495753675699234, -0.49565330147743225, -0.49555179476737976, -0.49544909596443176, -0.49534523487091064, -0.4952402114868164, -0.49513402581214905, -0.49502667784690857, -0.49491816759109497, -0.49480846524238586, -0.494697630405426, -0.4945856034755707, -0.4944724440574646, -0.494358092546463, -0.4942425787448883…]

0*x = -0.49......

Hä? Irgendwas stimmt hier ganz und gar nicht.

Selbes Problem auch hier:
Code:
<!DOCTYPE HTML>
<body>

Testing the webaudio bug...

<script>
    
function dB(buffer){
    var rms = 0, total = 0;
   for(var i=0;i<buffer.length;i++){
    total+= Math.abs(buffer[i]);
   }
   rms = Math.sqrt(total/buffer.length);
   return 20*(Math.log(rms)/Math.log(10));

    
}
    
var windowHann = function(sampleBuffer){
	var l = sampleBuffer.length;
	console.log(dB(sampleBuffer), sampleBuffer);
        var s=0;
	var arg = 2.0*Math.PI/(l-1);
	for(var i=0; i<l;i++){
	s = sampleBuffer[i] * 0.5-0.5 * Math.cos(arg*i);// nicht 0.5 * (1 - Math.cos(DSP.TWO_PI * index / (length - 1)));	
	if (s<-1 || s>1)s=1;
        sampleBuffer[i]=s;
        }
        console.log(dB(sampleBuffer), sampleBuffer);
};


function makeSine(){
    var sine = new Float32Array(192000);
    var pi = 4.0 * Math.atan(1.0);
    var x = 0;
    for(var i=0;i<sine.length;i++){
        sine[i] = 0.0//    0.006385 * Math.sin(x++/(192000/(1500*2*pi)))
    }
   
    windowHann(sine);
}

makeSine();
</script>
</body>
</html>
 
Zuletzt bearbeitet:
Falsch, wenn ich ein Fenster hab was 768Pixel lang ist und von rechts nach links rendert, in einem Intervall von 40ms und es wird im QRSS-3 Mode gemorst. Dann ist ein Punkt schon 3 Minuten lang und ein Stich 6 Minuten. Bei ein Intervall von 40ms weiß ich nicht sendet der eine Punkt oder Stich. Also muss ich den Intervall verlangsamen auf was weiß ich 300ms. Zusätlich muss ja ein komplettes Rufzeichen auf das Fenster passen nicht das der erste Buchstabe schon wider links verschwindet.
das eine ist die analyse, das andere die darstellung. du kannst das analyseintervall nicht von deinem darstellungsintervall abhängig machen.

+den Signal Rauschabstand, + der größe des Fensters. Was nützt ein 300Hz Spektrum auf einer länge von 3000Pixeln. Dann ist ein Stich ja Daumen dick, es seiden man erhöht die FFT.
das eine ist die analyse, das andere die darstellung, ...ich wiederhole mich

Ich habe die werte mal beggenzt auf -1 bis +1
begrenzt oder normiert?
via if(s<-1 || s>1)s=1;
also begrenzt. du musst schon verstehen, was du da überhaupt machst

Kommt das bei raus:
da kommt müll bei raus, du musst es (wenn überhaupt) normieren

0*x = -0.49......
Hä? Irgendwas stimmt hier ganz und gar nicht.
hatten wir schon, das ist nicht 0*x, sondern 0*x-y

- - - Aktualisiert - - -

ach und warum willst du eigentlich auf +-1 begrenzen? deine amplitude ist ja wesentlich kleiner
jedenfalls in diesem bsp.
 
tsseh schrieb:
begrenzt oder normiert?....also begrenzt. du musst schon verstehen, was du da überhaupt machst
Ich habe geschrieben begrenzt.

tsseh schrieb:
du kannst das analyseintervall nicht von deinem darstellungsintervall abhängig machen.
Das ist richtig, man muss halt einen Kompromiss zwischen analyseintervall und darstellungsintervall finden.


tsseh schrieb:
hatten wir schon, das ist nicht 0*x, sondern 0*x-y
Dann schreibe ich das Fenster so:
0.5 * (1 - Math.cos(DSP.TWO_PI * index / (length - 1)));


tsseh schrieb:
ach und warum willst du eigentlich auf +-1 begrenzen? deine amplitude ist ja wesentlich kleiner
will ich nicht, aber wenn nach der Berechnung Werte wie 5.069923147971167e-9, 1.198377574951337e-8, 2.332104642732702e-8 rauskommen dann ist das was Faul weil 1 sample nur +-1 max hat.

Apropos faul, gerendert wird immer noch müll, Träger die gar nicht existieren.
Seihe screenshot:
rendering.png
Rechtes bild ist Windows XP, das erzeugt anderes als Windows 7(links). Warum?
 
Zuletzt bearbeitet:
Das ist richtig, man muss halt einen Kompromiss zwischen analyseintervall und darstellungsintervall finden.
nein, das ist unabhängig voneinander,
du berechnest immer wenn dein puffer da ist und zeichnest alle daten, zu einem belibigen zeitpunkt, requestAnimationFrame würde sich hier anbieten.

Dann schreibe ich das Fenster so:
0.5 * (1 - Math.cos(DSP.TWO_PI * index / (length - 1)));
ja, oder du lässt die berechnung so wie sie war, warum willst du ständig deine formel umstellen?

will ich nicht, aber wenn nach der Berechnung Werte wie 5.069923147971167e-9, 1.198377574951337e-8, 2.332104642732702e-8 rauskommen dann ist das was Faul weil 1 sample nur +-1 max hat.
die alle im bereich +-1 liegen, nahe 0
das siehst du auch in dem diagram welches ich in #23 am ende angehängt habe

Apropos faul, gerendert wird immer noch müll, Träger die gar nicht existieren.
mit welchen daten?
wenn du deinen obigen sin als input für deine funktion nimmst, also z.b. alles was vorher kommt abklemmst, dann stimmt es nicht?
entweder zeichnest du dann falsch, oder du veränderst danach nochmal das signal.

- - - Aktualisiert - - -

Rechtes bild ist Windows XP, das erzeugt anderes als Windows 7(links). Warum?
keine ahnung
 
Zuletzt bearbeitet:
tsseh schrieb:
das siehst du auch in dem diagram welches ich in #23 am ende angehängt habe
ah ok das war bereits Gefenstert.

tsseh schrieb:
wenn du deinen obigen sin als input für deine funktion nimmst, also z.b. alles was vorher kommt abklemmst, dann stimmt es nicht?
Genau resampler steht auf bypass. Mehr kommt zuvor nicht. Das was gendert wir ist von System zu System anders. Das ist ja das verrückte. Das macht mich aaaalllleeee. :mad::mad::mad:



tsseh schrieb:
entweder zeichnest du dann falsch, oder du veränderst danach nochmal das signal.
Ahrrrrrr Du hast recht. Ich verändere zwar das Signal danach nicht mehr aber beim rendern scheint mir ein Fehler untergekommen zu sein. :mad:

Erklärt aber nicht warum das von System System unterschiedlich ist. Das schaue ich mir am Mo an... wenns brennt melde ich mich.
Habe kein bock mehr, jetzt wird SOMA gedaddelt.
 
Zuletzt bearbeitet:
ich hab mir jetzt nochmal den resampler angesehen.
dein outputBuffer ist größer ... warum eigentlich?
Code:
if(fromRate < toRate){//upsample
            this.ratio = fromRate/toRate;
            this.outputBuffer = new Float32Array(parseInt(length/this.ratio));
            this.resample = this.upSample;
            this.lpf = new audioLib.BiquadFilter.LowPass(toRate, toRate/2, 0.5);
        }else{//downsample
            this.ratio = toRate/fromRate;
            this.outputBuffer = new Float32Array(parseInt(length*this.ratio));
            this.resample = this.downSample;
            this.lpf = new audioLib.BiquadFilter.LowPass(toRate, toRate/2, 0.5);
        }
du hast hier auf jeden fall if und else vertauscht, dann ist aber im upsample noch die ratio falsch, die muss ja größer 1 werden. und outputBuffer hat eine länge von length*ratio.

beim downsample.
mal mit dem sin den wir immer hatten:
Anhang anzeigen orig.pdf
Anhang anzeigen audiolib.pdf
Anhang anzeigen deine.pdf
jetzt mal was schnelleres:
Anhang anzeigen osc_orig.pdf
Anhang anzeigen osc_orig_1bis100.pdf
Anhang anzeigen osc_audiolib.pdf
Anhang anzeigen osc_deine.pdf
Anhang anzeigen osc_beide.pdf
Anhang anzeigen osc_beide_1bis10.pdf
Anhang anzeigen osc_beide_1bis100.pdf

- - - Aktualisiert - - -

wenn ich mir deinem upsample-aalgorithmus ansehe, sieht der eigentlich ganz brauchbar aus.
ich teste das ganze bei gelegenheit mal mit diesem.
 
mit
Code:
ratio = toRate/audioCtx.sampleRate;
outputBuffer = new Float32Array(Math.ceil(data.length * ratio));
lpf = new audioLib.BiquadFilter.LowPass(toRate, toRate/2, 0.5);
aus deiner init funktion und
Code:
var length = data.length;
var pos = 0.0;
for(var i = 0; i < outputBuffer.length; i++)
{
  var inPos = parseInt(pos);
  var proportion = pos-inPos;
  if(inPos >= length-1)
  {
    inPos = length-2;
    proportion=1.0;
  }
  outputBuffer[i] = data[inPos] * (1.0 - proportion) + data[inPos + 1] * proportion;
  pos += 1/ratio;
}
//Perform Anti-alasing lowPass    
for(var j = 0; j < outputBuffer.length; j++)
{
  lpf.pushSample(outputBuffer[j]);
  outputBuffer[j] = lpf.getMix();
}
console.log(outputBuffer.join("\",\""));
aus der upsample (data war mein input, bei dir buffer) bekomme ich das gleiche ergebniss wie bei der audiolib
Anhang anzeigen osc_beide_1bis100_upsample.pdf

- - - Aktualisiert - - -

das ganze jetzt noch upgesamplet auf 88888Hz
Anhang anzeigen osc_beide_1bis100_upsample2.pdf
am ende der kurve, wo folgewerte fehlen, weil über den letzten punkt der alten kurve hinausberechnet wird, haben du und die audiolib unterschiedliche strategien. aber dort kann man nichts machen ohne auf den nächsten puffer zu warten
Anhang anzeigen osc_beide_letzte100_upsample.pdf
edit: wobei ich deine strategie dort für fragwürdig halte
 
Zuletzt bearbeitet:
Cool, vielviel dank das Du dir den Resampler noch mal anschaust.
Jedenfalls funktionirt das Rendern immer noch nicht! Es war auch kein fehler beim rendern zu finden.

Ich habe mal alles soweit weggelöcht was nicht für das rendern genutzt wird.
Code:
<!DOCTYPE html>

<head>
  <meta charset="utf-8">
  <title>RT Grabber Normal-CW-Mediumwave by DL3ARM</title>

  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
  <script src="http://rtg-test.sytes.net/grabber/lib/audiolib.js"></script>
  <script src="http://rtg-test.sytes.net/grabber/lib/chroma.js"></script>
  <script>
    function player(ID, URL) {
      //Audio Stuff
      if (!window.AudioContext) {
        if (!window.webkitAudioContext) {
          alert("no audiocontext found!");
        }
        window.AudioContext = window.webkitAudioContext;
      }
      this.x = 0;
      this.audioctx = new AudioContext();
      this.w_ptr = 0;
      this.r_ptr = 30720;
      this.bufferSize = 32768;
      this.IntBuffer = new Int16Array(this.bufferSize);
      this.InRate = 8000; //hz
      this.outputBuffer = new Float32Array(4096); //this Array goes to the otehr objects (Resampler, windowFunctions)
      this.p = null;
      this.OutRate = this.audioctx.sampleRate;
      //this.N_of_samples = 4096; //number of samples where Script Processor play through
      this.coefs = this.calcCoeffs(this.OutRate, this.InRate, 256); //calculate the lowpass coefficients
      this.delayLine = new Float32Array(this.coefs.length);
      this.count = 0;
      //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(URL);
    }

    player.prototype.init = function() {
      this.connection();
    };

    player.prototype.calcCoeffs = function(SR, cutOff, len) {
      len += (len + 1) % 2;
      var freq = cutOff / SR;
      var coefs = new Float32Array(len);
      var center = Math.floor(len / 2);
      var sum = 0;
      for (var i = 0; i < len; ++i) {
        var val;
        if (i == center) {
          val = 2 * Math.PI * freq;
        } else {
          var angle = 2 * Math.PI * (i + 1) / (len + 1);
          val = Math.sin(2 * Math.PI * freq * (i - center)) / (i - center);
          val *= 0.42 - 0.5 * Math.cos(angle) + 0.08 * Math.cos(2 * angle);
        }
        sum += val;
        coefs[i] = val;
      }
      for (var i = 0; i < len; ++i) {
        coefs[i] /= sum;
      }
      return coefs;
    };

    //connect the web audio Node
    player.prototype.connection = function() {
      var Processor;
      if (this.audioctx.createScriptProcessor) {
        Processor = this.audioctx.createScriptProcessor(4096, 0, 1);
      } else {
        Processor = this.audioctx.createjavaScriptNode(4096, 1, 1);
      }

      //  var Processor = this.audioctx.createScriptProcessor(4096, 0, 1);
      Processor.onaudioprocess = this.play.bind(this);
      Processor.connect(this.audioctx.destination);
    };

    player.prototype.SamplesCallback = function() {};
    player.prototype.dBCallback = function() {};

    player.prototype.getSampleRate = function() {
      return this.audioctx.sampleRate;
    };

    player.prototype.play = function(ev) {
        var outputLeft = ev.outputBuffer.getChannelData(0);
        var Len = ev.outputBuffer.length;
        var total = 0; //var for decibel calculation
        var rms = 0; //Root Mean Square
        var decibel = 0;
        for (var j = 0; j < Len; j++) {
          var sample = this.IntBuffer[this.r_ptr];
          var ratio = this.pBs * this.InRate / this.OutRate;
          this.ratioWeight += ratio;
          // Sample Rate calibration
          if (1 <= this.ratioWeight) {
            this.ratioWeight -= 1;
            this.IntBuffer[this.r_ptr] = 0.0;
            this.r_ptr++;
            if (this.bufferSize <= this.r_ptr) this.r_ptr -= this.bufferSize;
            var sample2 = this.IntBuffer[this.r_ptr];
            sample = (this.ratioWeight * sample2 + (ratio - this.ratioWeight) * sample) / ratio;
          }
          sample = sample > 0 ? sample / 32767.0 : sample / 32768.0;
          //detect clipping errors
          if (sample < -1) sample = -1;
          if (sample > 1) sample = 1;
          //FIR Lowpass Filter
          this.delayLine[this.count] = sample;
          var FIR_out = 0.0;
          var idx = this.count;
          for (var i = 0; i < this.coefs.length; i++) {
            FIR_out += this.coefs[i] * this.delayLine[idx--];
            if (idx < 0) idx = this.coefs.length - 1;
          }
          if (++this.count >= this.coefs.length) this.count = 0;
          sample = FIR_out;
          //summ of all 4096 samples   
          total += Math.abs(sample);
          this.outputBuffer[j] = 0.06523 * Math.sin(this.x++/(this.audioctx.sampleRate/ (1500 * 2 * Math.PI))) //sample; //sound output
        if (this.x > this.audioctx.sampleRate) this.x = 0;
      } //ende for
    outputLeft.set(this.outputBuffer);
    this.SamplesCallback(this.outputBuffer);
    //calc decibel
    rms = Math.sqrt(total / Len);
    decibel = 20 * (Math.log(rms) / Math.log(10));
    this.dBCallback(decibel);
    this.SPTime = this.audioctx.currentTime; //(new Date).getTime();
    };

    player.prototype.getSamples = function(URL) {
      var that = this;
      var ws = new WebSocket(URL);
      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 > 3E3) {
          that.r_ptr = (that.bufferSize + that.w_ptr - 1E3) % that.bufferSize;
          jit = response_speed = 1E3;
        }
        that.pBs = 1 + 1E-5 * (response_speed - 1E3);
        if (1.002 < that.pBs) that.pBs = 1.002;
        if (0.998 > that.pBs) that.pBs = 0.998;
        var dv = new DataView(b.data);
        that.InRate = dv.getUint16(0); //Get the Samplerate from the Buffer
        var I16 = new Int16Array(b.data),
          i = 1; //i=1 weil die ersten 2 byte die Samplrate sind 
        while (i < I16.length) {
          that.w_ptr++, i++;
          that.IntBuffer[that.w_ptr] = I16[i];
          if (that.bufferSize <= that.w_ptr) that.w_ptr -= that.bufferSize;
        };
      };
    };

    function wf(defaultWindow, id, alpha) {
      this.alpha = alpha;
      this.Pi2 = Math.PI * 2;
      this.ID = id;
      this.init(defaultWindow);

    }

    wf.prototype.init = function(type) {
      switch (type) {
        case "Hamming":
          this.performWindow = this.windowHamming;
          break;

        case "Hann":
          this.performWindow = this.windowHann;
          break;

        case "Bartlett":
          this.performWindow = this.windowBartlett;
          break;

        case "BartlettHann":
          this.performWindow = this.windowBartlettHann;
          break;

        case "Blackman":
          this.performWindow = this.windowBlackman;
          this.alpha = this.alpha || 0.16;
          break;

        case "Cosine":
          this.performWindow = this.windowCosine;
          break;

        case "Gauss":
          this.performWindow = this.windowGauss;
          this.alpha = this.alpha || 0.25;
          break;

        case "Triangular":
          this.performWindow = this.windowTriangular;
          break;

        case "Lanczos":
          this.performWindow = this.windowLanczos;
          break;

        case "Rectangular":
          this.performWindow = this.bypassWindow;
          break;

      }
    };

    wf.prototype.windowCallback = function() {};

    wf.prototype.windowHann = function(sampleBuffer) {
      var l = sampleBuffer.length;
      var arg = 2.0 * Math.PI / (l - 1);
      for (var i = 0; i < l; i++) {
        sampleBuffer[i] *= 0.5-0.5*Math.cos(arg*i)//0.5 * (1 - Math.cos(this.Pi2 * i / (l - 1)));
      }
      this.windowCallback(sampleBuffer);
    };

    wf.prototype.windowHamming = function(sampleBuffer) {
      var l = sampleBuffer.length;
      for (var i = 0; i < l; i++) {
        sampleBuffer[i] *= 0.54 - 0.46 * Math.cos(this.Pi2 * i / (l - 1));
      }
      this.windowCallback(sampleBuffer);
    };

    wf.prototype.windowBartlett = function(sampleBuffer) {
      var l = sampleBuffer.length;
      for (var i = 0; i < l; i++) {
        sampleBuffer[i] *= 2 / (l - 1) * ((l - 1) / 2 - Math.abs(i - (l - 1) / 2));
      }
      this.windowCallback(sampleBuffer);
    };

    wf.prototype.windowBartlettHann = function(sampleBuffer) {
      var l = sampleBuffer.length;
      for (var i = 0; i < l; i++) {
        sampleBuffer[i] *= 0.62 - 0.48 * Math.abs(i / (l - 1) - 0.5) - 0.38 * Math.cos(this.Pi2 * i / (l - 1));
      }
      this.windowCallback(sampleBuffer);
    };

    wf.prototype.windowBlackman = function(sampleBuffer) {
      var l = sampleBuffer.length;
      var a0 = (1 - this.alpha) / 2;
      var a1 = 0.5;
      var a2 = this.alpha / 2;
      for (var i = 0; i < l; i++) {
        sampleBuffer[i] *= a0 - a1 * Math.cos(this.Pi2 * i / (l - 1)) + a2 * Math.cos(4 * this.pi * i / (l - 1));
      }
      this.windowCallback(sampleBuffer);
    };

    wf.prototype.windowCosine = function(sampleBuffer) {
      var l = sampleBuffer.length;
      for (var i = 0; i < l; i++) {
        sampleBuffer[i] *= Math.cos(Math.PI * i / (l - 1) - this.pi / 2);
      }
      this.windowCallback(sampleBuffer);
    };

    wf.prototype.windowGauss = function(sampleBuffer) {
      var l = sampleBuffer.length;
      for (var i = 0; i < l; i++) {
        sampleBuffer[i] *= Math.pow(Math.E, -0.5 * Math.pow((i - (l - 1) / 2) / (this.alpha * (l - 1) / 2), 2));
      }
      this.windowCallback(sampleBuffer);
    };

    wf.prototype.windowTriangular = function(sampleBuffer) {
      var l = sampleBuffer.length;
      for (var i = 0; i < l; i++) {
        sampleBuffer[i] *= 2 / l * (l / 2 - Math.abs(i - (l - 1) / 2));
      }
      this.windowCallback(sampleBuffer);
    };

    wf.prototype.windowLanczos = function(sampleBuffer) {
      var l = sampleBuffer.length;
      for (var i = 0; i < l; i++) {
        var x = 2 * i / (l - 1) - 1;
        sampleBuffer[i] *= Math.sin(Math.PI * x) / (Math.PI * x);
      }
      this.windowCallback(sampleBuffer);
    };


    wf.prototype.bypassWindow = function(sampleBuffer) {
      this.windowCallback(sampleBuffer);
    };

    wf.prototype.setWindowFunc = function(windowFunc) {
      if (typeof windowFunc === 'string') {
        this.init(windowFunc);
      } else {
        console.log("WindowFunction isn't a string");
      }
    };

    function Window(ID, GrabberID, ColorScalHelper_ClassID, FFT_InfoId) {
      this.GrabberID = GrabberID
      this.id = ID; //the id of the all widnows has the same id as the player class 
      this.SR = 0; // Samplerate in Hz
      this.Si = 40; //Scrollintervall
      this.fftSize = 0;
      this.Analyser1 = null;
      this.F_min = 0; //min Frequncy
      this.F_max = 0; // max Frequnecy
      this.Offs = 0;
      this.beginScale = 280; // position where begin the frequency scale in px 
      this.Decibel = 0;
      this.WebAudiorate = 0;
      this.interval = null;

      //main Canvas
      this.canvas = document.getElementById("canvas");
      this.canvas_width = this.canvas.width;
      this.canvas_height = this.canvas.height;
      this.canvas_ctx = this.canvas.getContext("2d");
      this.canvas_ctx.strokeStyle = "red";
      this.canvas_ctx.lineWidth = "1.2";
      this.canvas_ctx.imageSmoothingEnabled = false;

      //TempCanvas wird benoetig f�r wasserfall canvas
      this.tempCanvas = document.createElement("canvas");
      this.tempCtx = this.tempCanvas.getContext("2d");
      this.tempCanvas.width = this.canvas_width - this.beginScale - 1;
      this.tempCanvas.height = this.canvas_height;
      this.tempCtx.imageSmoothingEnabled = false;
      //Wasservall Canvas
      this.waterCanvas = document.createElement("canvas");
      this.waterCanvas.width = this.canvas_width - this.beginScale - 1;
      this.waterCanvas.height = this.canvas_height;
      this.waterCanvasCtx = this.waterCanvas.getContext('2d');
      this.waterCanvasCtx.imageSmoothingEnabled = false;

      //chromajs 
      this.contrast = 1;
      this.brightness = 1;
      this.colors = null;
      this.color_array = null;
      this.resetChroma();
      this.fftInfoId = FFT_InfoId;
    }

    Window.prototype.calcDrawValues = function() {
      this.binWidth = this.SR / this.fftSize;
      var diff = this.F_max - this.F_min + 1;
      this.F_Start = (this.F_min - this.Offs) / this.binWidth;
      //ist F_Start negativ dann mache positiv
      if (this.F_Start < 0) this.F_Start *= -1;
      var F_end = (this.F_max - this.Offs) / this.binWidth;
      //istF_end negativ damm mache positiv
      if (F_end < 0) F_end *= -1;
      this.fftArrayIdx = diff / this.binWidth;
    };

    Window.prototype.setSamplerate = function(SR, WebAudiorate) {
      //Check if argument Web audiorate is passed 
      if (typeof WebAudiorate !== "undefined") {
        this.WebAudiorate = WebAudiorate;
      }
      this.SR = parseInt(SR);
      this.calcDrawValues();
      this.resetFFT();
    };

    //Setter for fft input buffer size
    Window.prototype.setFFT_size = function(InpBufferLen) {
      this.fftSize = parseInt(InpBufferLen);
      this.resetFFT();
      this.calcDrawValues();
      // this.renderFreqencyScale(this.F_min, this.F_max);
    };

    Window.prototype.resetFFT = function() {
      if (this.SR > 0 && this.fftSize > 0) {
        clearTimeout(this.interval);
        this.Analyser1 = new audioLib.FFT(this.SR, this.fftSize);
          //delay 10 ms when not browser freeze, before check if intevall is startet
        if (this.interval !== null) {
          //  setTimeout(this.StartInterval(), 10);
        }
      }
    }

    Window.prototype.resetChroma = function() {
      if (this.contrast != 0 || this.brightness != 0) {
        clearTimeout(this.interval);
        this.colors = new chroma.ColorScale({
          colors: ['#000000', '#0B16B5', '#FFF782', '#EB1250'],
          mode: 'rgb',
          limits: [0, 50]
        });
      }
    };

    Window.prototype.setFrequency = function(F_min, F_max, LoFreq) {
      this.F_max = parseFloat(F_max);
      this.F_min = parseFloat(F_min);
      this.Offs = parseFloat(LoFreq);
      this.calcDrawValues();
    };


    Window.prototype.setScrollIntervall = function(ms) {
      if (this.interval != null) {
        clearTimeout(this.interval);
      }
      ms = parseInt(ms);
      this.Si = ms;
      this.StartInterval()
    };



    Window.prototype.round = function(Zahl, n) {
      var faktor = Math.pow(10, n);
      return Math.round(Zahl * faktor) / faktor;
    };

    Window.prototype.StartInterval = function() {
      var that = this;
      var animationInterval;
      (animationInterval = function() {
        that.drawSpectrogram();
        that.interval = setTimeout(animationInterval, that.Si);

      })();

    };

    Window.prototype.pushSamples = function(samples) {
      for (var i = 0; i < samples.length; i++) {
        this.Analyser1.pushSample(samples[i]);
      }
    };

    Window.prototype.drawSpectrogram = function() {
      var ctx = this.canvas_ctx;
      ctx.clearRect(this.beginGrid, 0, this.db_GridWidth, this.canvas_height);

      var FFT_Data = this.Analyser1.spectrum;
      this.tempCtx.drawImage(this.waterCanvas, 0, 0, this.waterCanvas.width, this.waterCanvas.height);

      for (var i = 0; i < this.canvas_height; i++) {
        var pt = Math.floor(this.F_Start + this.fftArrayIdx / this.canvas.height * i);
        var v1 = FFT_Data[pt] * Math.pow(10, 10);
        // draw each pixel with the specific color
        //wait for the cromajs getColor() methode
        if (!!this.colors.getColor()) {
          this.waterCanvasCtx.fillStyle = this.colors.getColor(v1).hex();
        }
        this.waterCanvasCtx.fillRect(this.waterCanvas.width - 1, this.waterCanvas.height - i, 1, 1);
      }
      // set translate on the canvas
      this.waterCanvasCtx.translate(-1, 0);
      // draw the copied image
      this.waterCanvasCtx.drawImage(this.tempCanvas, 0, 0, this.waterCanvas.width, this.waterCanvas.height, 0, 0, this.waterCanvas.width, this.waterCanvas.height);
      // reset the transformation matrix
      this.waterCanvasCtx.setTransform(1, 0, 0, 1, 0, 0);
      //draw the water canvas on the main cnavas 
      ctx.drawImage(this.waterCanvas, 0, 0, this.waterCanvas.width, this.waterCanvas.height, 0, 0, this.waterCanvas.width + 1, this.waterCanvas.height);

    };

    $(document).ready(function() {
      var GrabberStack = {};
      GrabberStack.Normal_CW = {};
      var FFT_Length = 8192;
      var ScrollInter = 60; //ms
      var FensterFunctionWindow = "Hann"

      GrabberStack["Player"] = new player("blabla", "ws://" + window.location.hostname + ":" + "3045");

      GrabberStack["Normal_CW"]["Window"] = new Window()
      GrabberStack["Normal_CW"]["DSP_Window"] = new wf(FensterFunctionWindow, "bla");
      //set values on window 
      GrabberStack["Normal_CW"]["Window"].setSamplerate(GrabberStack.Player.getSampleRate(), GrabberStack.Player.getSampleRate());
      GrabberStack["Normal_CW"]["Window"].setFrequency(0, 2500, 0);
      GrabberStack["Normal_CW"]["Window"].setFFT_size(FFT_Length);
      GrabberStack["Normal_CW"]["Window"].setScrollIntervall(ScrollInter);
      //set callbacks
      GrabberStack["Normal_CW"]["DSP_Window"].windowCallback = function(windowSample) {
          GrabberStack["Normal_CW"]["Window"].pushSamples(windowSample);
        }
        //not used the measured decibels
      GrabberStack.Player.dBCallback = function(dB) {
        //document.getElementById("dB").innerHTML = dB +"    dB";
        //normal_cw_widnow.setDecibel(dB);
      }

      GrabberStack.Player.SamplesCallback = function(sampleBuffer) {

          GrabberStack["Normal_CW"]["DSP_Window"].performWindow(sampleBuffer);

        } // ende .SamplesCallback 
      GrabberStack["Player"].init();

    });
  </script>

  <body>
    <canvas id="canvas" width="1024" height="768" style="display: block; background-color: black ;"></canvas>
  </body>

  </html>
Die 2te Scriptnode habe ich auch noch entfernt... wird nicht mher benötigt.

Bei mir werden im abstand von 10Hz Striche über das Spektum gerendert. Es ist föllig egal welches Fenter man nimmt das Ergebis ist immr gleich. Nur das Rectagular Fenster geht!

Du brauchst eigelich nur den code via copie paste zu Kopiren und bei dir auszüfunren. Ich bezweifle das es bei dir funzt, weil das Problem ist auf allen Rechern das gleiche.

Ich habe mich Zwichendurch auch mal mit R beschäftigt. Hm ich weiß nicht so recht für statistisches Rechnen und Plotten hab ich immer Python genommen.

Ach und wenn ich das vertausche:
outputLeft.set(this.outputBuffer);
this.SamplesCallback(this.outputBuffer);
also erst callback und dann set, dann zirpst der Ton auch wider:confused:
 
Zuletzt bearbeitet:
der rest später, muss ich mir mal ansehen(heute abend)
Ach und wenn ich das vertausche:
outputLeft.set(this.outputBuffer);
this.SamplesCallback(this.outputBuffer);
also erst callback und dann set, dann zirpst der Ton auch wider:confused:
outputBuffer ist ein objekt.
in js wird zwar alle parameter ByCopy an funktionen übergeben, allerdings sind objekte selbst referenzen.
also wirkt sich, wenn du ein objekt an eine funktion übergibst, und dieses objekt in der funktion veränderst, diese änderung auch außerhalb der funktion aus.
SamplesCallback verändert also dein objekt.
 
also wirkt sich, wenn du ein objekt an eine funktion übergibst, und dieses objekt in der funktion veränderst, diese änderung auch außerhalb der funktion aus.
Asso, das erklärt einiges. Man bräuchte also sowas wie memcpy in C.

Der Sinus ist nach wie vor der selbe: this.outputBuffer[j] = 0.06523 * Math.sin(this.x++/(this.audioctx.sampleRate/ (1500 * 2 * Math.PI)))
Das Spektrum geht von 0-2500 Hz GrabberStack["Normal_CW"]["Window"].setFrequency(0, 2500, 0);

tsseh schrieb:
der rest später, muss ich mir mal ansehen(heute abend)
Jo, mach in ruhe.
 
Zuletzt bearbeitet von einem Moderator:
Der Sinus ist nach wie vor der selbe: this.outputBuffer[j] = 0.06523 * Math.sin(this.x++/(this.audioctx.sampleRate/ (1500 * 2 * Math.PI)))
bei mir, mit einer samplerate von 48000 passt erst mal das ergebniss der fft:
> sum(as.numeric(w))
[1] 0.06523787
Anhang anzeigen 4709
ich hab mal die fft size auf 4096 gestellt, damit habe ich eine bandbreite von 11,71875
und damit liegen die 1500Hz bei 128
das sieht man auch im diagram(achtung, beginnt bei 101)
also zeichnest du falsch. auf jedenfall scheint deine farbscalierung schon mal nicht zu passen.
dann hast du alle ~10 intervalle einen überschlag von this.x bei deiner berechnung des sin, dadurch (und durch deine farbscalierung) kommen die senkrechten striche alle ~10 intervalle(das ist aber ja nur hier für den test interessant)
die berechnung des bereiches, welchen du darstellen möchtest sieht komisch aus
muss ich mir mal genauer ansehen

- - - Aktualisiert - - -

wenn du deine farbscalierung in ordnung bringst, geht es schon
Code:
<!DOCTYPE html>

<head>
  <meta charset="utf-8">
  <title>RT Grabber Normal-CW-Mediumwave by DL3ARM</title>

  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
  <script src="http://rtg-test.sytes.net/grabber/lib/audiolib.js"></script>
  <script src="http://rtg-test.sytes.net/grabber/lib/chroma.js"></script>
  <script>
    function player(ID, URL) {
      //Audio Stuff
      if (!window.AudioContext) {
        if (!window.webkitAudioContext) {
          alert("no audiocontext found!");
        }
        window.AudioContext = window.webkitAudioContext;
      }
      this.x = 0;
      this.audioctx = new AudioContext();
      this.w_ptr = 0;
      this.r_ptr = 30720;
      this.bufferSize = 32768;
      this.IntBuffer = new Int16Array(this.bufferSize);
      this.InRate = 8000; //hz
      this.outputBuffer = new Float32Array(4096); //this Array goes to the otehr objects (Resampler, windowFunctions)
      this.p = null;
      this.OutRate = this.audioctx.sampleRate;
      //this.N_of_samples = 4096; //number of samples where Script Processor play through
      this.coefs = this.calcCoeffs(this.OutRate, this.InRate, 256); //calculate the lowpass coefficients
      this.delayLine = new Float32Array(this.coefs.length);
      this.count = 0;
      //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(URL);
    }

    player.prototype.init = function() {
      this.connection();
    };

    player.prototype.calcCoeffs = function(SR, cutOff, len) {
      len += (len + 1) % 2;
      var freq = cutOff / SR;
      var coefs = new Float32Array(len);
      var center = Math.floor(len / 2);
      var sum = 0;
      for (var i = 0; i < len; ++i) {
        var val;
        if (i == center) {
          val = 2 * Math.PI * freq;
        } else {
          var angle = 2 * Math.PI * (i + 1) / (len + 1);
          val = Math.sin(2 * Math.PI * freq * (i - center)) / (i - center);
          val *= 0.42 - 0.5 * Math.cos(angle) + 0.08 * Math.cos(2 * angle);
        }
        sum += val;
        coefs[i] = val;
      }
      for (var i = 0; i < len; ++i) {
        coefs[i] /= sum;
      }
      return coefs;
    };

    //connect the web audio Node
    player.prototype.connection = function() {
      var Processor;
      if (this.audioctx.createScriptProcessor) {
        Processor = this.audioctx.createScriptProcessor(4096, 0, 1);
      } else {
        Processor = this.audioctx.createjavaScriptNode(4096, 1, 1);
      }

      //  var Processor = this.audioctx.createScriptProcessor(4096, 0, 1);
      Processor.onaudioprocess = this.play.bind(this);
      Processor.connect(this.audioctx.destination);
    };

    player.prototype.SamplesCallback = function() {};
    player.prototype.dBCallback = function() {};

    player.prototype.getSampleRate = function() {
      return this.audioctx.sampleRate;
    };

    player.prototype.play = function(ev) {
        this.x = 0;
        var outputLeft = ev.outputBuffer.getChannelData(0);
        var Len = ev.outputBuffer.length;
        var total = 0; //var for decibel calculation
        var rms = 0; //Root Mean Square
        var decibel = 0;
        for (var j = 0; j < Len; j++) {
          var sample = this.IntBuffer[this.r_ptr];
          var ratio = this.pBs * this.InRate / this.OutRate;
          this.ratioWeight += ratio;
          // Sample Rate calibration
          if (1 <= this.ratioWeight) {
            this.ratioWeight -= 1;
            this.IntBuffer[this.r_ptr] = 0.0;
            this.r_ptr++;
            if (this.bufferSize <= this.r_ptr) this.r_ptr -= this.bufferSize;
            var sample2 = this.IntBuffer[this.r_ptr];
            sample = (this.ratioWeight * sample2 + (ratio - this.ratioWeight) * sample) / ratio;
          }
          sample = sample > 0 ? sample / 32767.0 : sample / 32768.0;
          //detect clipping errors
          if (sample < -1) sample = -1;
          if (sample > 1) sample = 1;
          //FIR Lowpass Filter
          this.delayLine[this.count] = sample;
          var FIR_out = 0.0;
          var idx = this.count;
          for (var i = 0; i < this.coefs.length; i++) {
            FIR_out += this.coefs[i] * this.delayLine[idx--];
            if (idx < 0) idx = this.coefs.length - 1;
          }
          if (++this.count >= this.coefs.length) this.count = 0;
          sample = FIR_out;
          //summ of all 4096 samples   
          total += Math.abs(sample);
          this.outputBuffer[j] = 0.06523 * Math.sin(this.x++/(this.audioctx.sampleRate/ (1500 * 2 * Math.PI))) //sample; //sound output
        if (this.x > this.audioctx.sampleRate) this.x = 0;
      } //ende for
    outputLeft.set(this.outputBuffer);
    this.SamplesCallback(this.outputBuffer);
    //calc decibel
    rms = Math.sqrt(total / Len);
    decibel = 20 * (Math.log(rms) / Math.log(10));
    this.dBCallback(decibel);
    this.SPTime = this.audioctx.currentTime; //(new Date).getTime();
    };

    player.prototype.getSamples = function(URL) {
      var that = this;
      var ws = new WebSocket(URL);
      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 > 3E3) {
          that.r_ptr = (that.bufferSize + that.w_ptr - 1E3) % that.bufferSize;
          jit = response_speed = 1E3;
        }
        that.pBs = 1 + 1E-5 * (response_speed - 1E3);
        if (1.002 < that.pBs) that.pBs = 1.002;
        if (0.998 > that.pBs) that.pBs = 0.998;
        var dv = new DataView(b.data);
        that.InRate = dv.getUint16(0); //Get the Samplerate from the Buffer
        var I16 = new Int16Array(b.data),
          i = 1; //i=1 weil die ersten 2 byte die Samplrate sind 
        while (i < I16.length) {
          that.w_ptr++, i++;
          that.IntBuffer[that.w_ptr] = I16[i];
          if (that.bufferSize <= that.w_ptr) that.w_ptr -= that.bufferSize;
        };
      };
    };

    function wf(defaultWindow, id, alpha) {
      this.alpha = alpha;
      this.Pi2 = Math.PI * 2;
      this.ID = id;
      this.init(defaultWindow);

    }

    wf.prototype.init = function(type) {
      switch (type) {
        case "Hamming":
          this.performWindow = this.windowHamming;
          break;

        case "Hann":
          this.performWindow = this.windowHann;
          break;

        case "Bartlett":
          this.performWindow = this.windowBartlett;
          break;

        case "BartlettHann":
          this.performWindow = this.windowBartlettHann;
          break;

        case "Blackman":
          this.performWindow = this.windowBlackman;
          this.alpha = this.alpha || 0.16;
          break;

        case "Cosine":
          this.performWindow = this.windowCosine;
          break;

        case "Gauss":
          this.performWindow = this.windowGauss;
          this.alpha = this.alpha || 0.25;
          break;

        case "Triangular":
          this.performWindow = this.windowTriangular;
          break;

        case "Lanczos":
          this.performWindow = this.windowLanczos;
          break;

        case "Rectangular":
          this.performWindow = this.bypassWindow;
          break;

      }
    };

    wf.prototype.windowCallback = function() {};

    wf.prototype.windowHann = function(sampleBuffer) {
      var l = sampleBuffer.length;
      var arg = 2.0 * Math.PI / (l - 1);
      for (var i = 0; i < l; i++) {
        sampleBuffer[i] *= 0.5-0.5*Math.cos(arg*i)//0.5 * (1 - Math.cos(this.Pi2 * i / (l - 1)));
      }
      this.windowCallback(sampleBuffer);
    };

    wf.prototype.windowHamming = function(sampleBuffer) {
      var l = sampleBuffer.length;
      for (var i = 0; i < l; i++) {
        sampleBuffer[i] *= 0.54 - 0.46 * Math.cos(this.Pi2 * i / (l - 1));
      }
      this.windowCallback(sampleBuffer);
    };

    wf.prototype.windowBartlett = function(sampleBuffer) {
      var l = sampleBuffer.length;
      for (var i = 0; i < l; i++) {
        sampleBuffer[i] *= 2 / (l - 1) * ((l - 1) / 2 - Math.abs(i - (l - 1) / 2));
      }
      this.windowCallback(sampleBuffer);
    };

    wf.prototype.windowBartlettHann = function(sampleBuffer) {
      var l = sampleBuffer.length;
      for (var i = 0; i < l; i++) {
        sampleBuffer[i] *= 0.62 - 0.48 * Math.abs(i / (l - 1) - 0.5) - 0.38 * Math.cos(this.Pi2 * i / (l - 1));
      }
      this.windowCallback(sampleBuffer);
    };

    wf.prototype.windowBlackman = function(sampleBuffer) {
      var l = sampleBuffer.length;
      var a0 = (1 - this.alpha) / 2;
      var a1 = 0.5;
      var a2 = this.alpha / 2;
      for (var i = 0; i < l; i++) {
        sampleBuffer[i] *= a0 - a1 * Math.cos(this.Pi2 * i / (l - 1)) + a2 * Math.cos(4 * this.pi * i / (l - 1));
      }
      this.windowCallback(sampleBuffer);
    };

    wf.prototype.windowCosine = function(sampleBuffer) {
      var l = sampleBuffer.length;
      for (var i = 0; i < l; i++) {
        sampleBuffer[i] *= Math.cos(Math.PI * i / (l - 1) - this.pi / 2);
      }
      this.windowCallback(sampleBuffer);
    };

    wf.prototype.windowGauss = function(sampleBuffer) {
      var l = sampleBuffer.length;
      for (var i = 0; i < l; i++) {
        sampleBuffer[i] *= Math.pow(Math.E, -0.5 * Math.pow((i - (l - 1) / 2) / (this.alpha * (l - 1) / 2), 2));
      }
      this.windowCallback(sampleBuffer);
    };

    wf.prototype.windowTriangular = function(sampleBuffer) {
      var l = sampleBuffer.length;
      for (var i = 0; i < l; i++) {
        sampleBuffer[i] *= 2 / l * (l / 2 - Math.abs(i - (l - 1) / 2));
      }
      this.windowCallback(sampleBuffer);
    };

    wf.prototype.windowLanczos = function(sampleBuffer) {
      var l = sampleBuffer.length;
      for (var i = 0; i < l; i++) {
        var x = 2 * i / (l - 1) - 1;
        sampleBuffer[i] *= Math.sin(Math.PI * x) / (Math.PI * x);
      }
      this.windowCallback(sampleBuffer);
    };


    wf.prototype.bypassWindow = function(sampleBuffer) {
      this.windowCallback(sampleBuffer);
    };

    wf.prototype.setWindowFunc = function(windowFunc) {
      if (typeof windowFunc === 'string') {
        this.init(windowFunc);
      } else {
        console.log("WindowFunction isn't a string");
      }
    };

    function Window(ID, GrabberID, ColorScalHelper_ClassID, FFT_InfoId) {
      this.GrabberID = GrabberID
      this.id = ID; //the id of the all widnows has the same id as the player class 
      this.SR = 0; // Samplerate in Hz
      this.Si = 40; //Scrollintervall
      this.fftSize = 0;
      this.Analyser1 = null;
      this.F_min = 0; //min Frequncy
      this.F_max = 0; // max Frequnecy
      this.Offs = 0;
      this.beginScale = 280; // position where begin the frequency scale in px 
      this.Decibel = 0;
      this.WebAudiorate = 0;
      this.interval = null;

      //main Canvas
      this.canvas = document.getElementById("canvas");
      this.canvas_width = this.canvas.width;
      this.canvas_height = this.canvas.height;
      this.canvas_ctx = this.canvas.getContext("2d");
      this.canvas_ctx.strokeStyle = "red";
      this.canvas_ctx.lineWidth = "1.2";
      this.canvas_ctx.imageSmoothingEnabled = false;

      //TempCanvas wird benoetig f�r wasserfall canvas
      this.tempCanvas = document.createElement("canvas");
      this.tempCtx = this.tempCanvas.getContext("2d");
      this.tempCanvas.width = this.canvas_width - this.beginScale - 1;
      this.tempCanvas.height = this.canvas_height;
      this.tempCtx.imageSmoothingEnabled = false;
      //Wasservall Canvas
      this.waterCanvas = document.createElement("canvas");
      this.waterCanvas.width = this.canvas_width - this.beginScale - 1;
      this.waterCanvas.height = this.canvas_height;
      this.waterCanvasCtx = this.waterCanvas.getContext('2d');
      this.waterCanvasCtx.imageSmoothingEnabled = false;

      //chromajs 
      this.contrast = 1;
      this.brightness = 1;
      this.colors = null;
      this.color_array = null;
      this.resetChroma();
      this.fftInfoId = FFT_InfoId;
    }

    Window.prototype.calcDrawValues = function() {
      this.binWidth = this.SR / this.fftSize;
      var diff = this.F_max - this.F_min + 1;
      this.F_Start = (this.F_min - this.Offs) / this.binWidth;
      //ist F_Start negativ dann mache positiv
      if (this.F_Start < 0) this.F_Start *= -1;
      var F_end = (this.F_max - this.Offs) / this.binWidth;
      //istF_end negativ damm mache positiv
      if (F_end < 0) F_end *= -1;
      this.fftArrayIdx = diff / this.binWidth;
    };

    Window.prototype.setSamplerate = function(SR, WebAudiorate) {
      //Check if argument Web audiorate is passed 
      if (typeof WebAudiorate !== "undefined") {
        this.WebAudiorate = WebAudiorate;
      }
      this.SR = parseInt(SR);
      this.calcDrawValues();
      this.resetFFT();
    };

    //Setter for fft input buffer size
    Window.prototype.setFFT_size = function(InpBufferLen) {
      this.fftSize = parseInt(InpBufferLen);
      this.resetFFT();
      this.calcDrawValues();
      // this.renderFreqencyScale(this.F_min, this.F_max);
    };

    Window.prototype.resetFFT = function() {
      if (this.SR > 0 && this.fftSize > 0) {
        clearTimeout(this.interval);
        this.Analyser1 = new audioLib.FFT(this.SR, this.fftSize);
          //delay 10 ms when not browser freeze, before check if intevall is startet
        if (this.interval !== null) {
          //  setTimeout(this.StartInterval(), 10);
        }
      }
    }

    Window.prototype.resetChroma = function() {
      if (this.contrast != 0 || this.brightness != 0) {
        clearTimeout(this.interval);
        this.colors = new chroma.ColorScale({
          colors: ['#000000', '#0B16B5', '#FFF782', '#EB1250'],
          mode: 'rgb',
          limits: [0, 1]
        });
      }
    };

    Window.prototype.setFrequency = function(F_min, F_max, LoFreq) {
      this.F_max = parseFloat(F_max);
      this.F_min = parseFloat(F_min);
      this.Offs = parseFloat(LoFreq);
      this.calcDrawValues();
    };


    Window.prototype.setScrollIntervall = function(ms) {
      if (this.interval != null) {
        clearTimeout(this.interval);
      }
      ms = parseInt(ms);
      this.Si = ms;
      this.StartInterval()
    };



    Window.prototype.round = function(Zahl, n) {
      var faktor = Math.pow(10, n);
      return Math.round(Zahl * faktor) / faktor;
    };

    Window.prototype.StartInterval = function() {
      var that = this;
      var animationInterval;
      (animationInterval = function() {
        that.drawSpectrogram();
        that.interval = setTimeout(animationInterval, that.Si);

      })();

    };

    Window.prototype.pushSamples = function(samples) {
      for (var i = 0; i < samples.length; i++) {
        this.Analyser1.pushSample(samples[i]);
      }
    };

    Window.prototype.drawSpectrogram = function() {
      var ctx = this.canvas_ctx;
      ctx.clearRect(0, 0, this.db_GridWidth, this.canvas_height);

      var FFT_Data = this.Analyser1.spectrum;
      this.tempCtx.drawImage(this.waterCanvas, 0, 0, this.waterCanvas.width, this.waterCanvas.height);

      for (var i = 0; i < this.canvas_height; i++) {
        var pt = Math.floor(this.F_Start + this.fftArrayIdx / this.canvas.height * i);
        var v1 = this.Analyser1.peak ? FFT_Data[pt] / this.Analyser1.peak : 0;
        // draw each pixel with the specific color
        //wait for the cromajs getColor() methode
        if (!!this.colors.getColor()) {
          this.waterCanvasCtx.fillStyle = this.colors.getColor(v1).hex();
        }
        this.waterCanvasCtx.fillRect(this.waterCanvas.width - 1, this.waterCanvas.height - i, 1, 1);
      }
      // set translate on the canvas
      this.waterCanvasCtx.translate(-1, 0);
      // draw the copied image
      this.waterCanvasCtx.drawImage(this.tempCanvas, 0, 0, this.waterCanvas.width, this.waterCanvas.height, 0, 0, this.waterCanvas.width, this.waterCanvas.height);
      // reset the transformation matrix
      this.waterCanvasCtx.setTransform(1, 0, 0, 1, 0, 0);
      //draw the water canvas on the main cnavas 
      ctx.drawImage(this.waterCanvas, 0, 0, this.waterCanvas.width, this.waterCanvas.height, 0, 0, this.waterCanvas.width + 1, this.waterCanvas.height);

    };

    $(document).ready(function() {
      var GrabberStack = {};
      GrabberStack.Normal_CW = {};
      var FFT_Length = 8192;
      var ScrollInter = 60; //ms
      var FensterFunctionWindow = "Hann"

      GrabberStack["Player"] = new player("blabla", "ws://" + window.location.hostname + ":" + "3045");

      GrabberStack["Normal_CW"]["Window"] = new Window()
      GrabberStack["Normal_CW"]["DSP_Window"] = new wf(FensterFunctionWindow, "bla");
      //set values on window 
      console.log(GrabberStack.Player.getSampleRate());
      GrabberStack["Normal_CW"]["Window"].setSamplerate(GrabberStack.Player.getSampleRate(), GrabberStack.Player.getSampleRate());
      GrabberStack["Normal_CW"]["Window"].setFrequency(0, 2500, 0);
      GrabberStack["Normal_CW"]["Window"].setFFT_size(FFT_Length);
      GrabberStack["Normal_CW"]["Window"].setScrollIntervall(ScrollInter);
      //set callbacks
      GrabberStack["Normal_CW"]["DSP_Window"].windowCallback = function(windowSample) {
          GrabberStack["Normal_CW"]["Window"].pushSamples(windowSample);
        }
        //not used the measured decibels
      GrabberStack.Player.dBCallback = function(dB) {
        //document.getElementById("dB").innerHTML = dB +"    dB";
        //normal_cw_widnow.setDecibel(dB);
      }

      GrabberStack.Player.SamplesCallback = function(sampleBuffer) {

          GrabberStack["Normal_CW"]["DSP_Window"].performWindow(sampleBuffer);

        } // ende .SamplesCallback 
      GrabberStack["Player"].init();

    });
  </script>

  <body>
    <canvas id="canvas" width="1024" height="768" style="display: block; background-color: black ;"></canvas>
  </body>

  </html>
ich hab einfach auf die größte amplitude normiert, keine ahnung, was du hier möchtest, vielleicht eher auf die gesamt-amplitude
deiner berechnung des bereiches scheint zu stimmen, ist aber "komisch", kannst du dir ja bei gelegenheit mal ansehen
 
tsseh schrieb:
deiner berechnung des bereiches scheint zu stimmen, ist aber "komisch", kannst du dir ja bei gelegenheit mal ansehen
Komisch ist das da ober und unterhalb des Tärger noch was ist und das dar nicht sein. Wenn man das Hann window raus nimmt ist das auch weg.

Ich möchte über 2 Slider noch Helligkeit und Kontrast mit einbringen um schwache Signal besser hervor heben zu können.
Da ich das noch nicht implementiert habe, habe ich das signal einfach via MAth.pow(10,10) verstärkt und da kommen Träger mit zum Vorschein die dürfen nicht sein. Ist das bei dir nicht so??
Alo ich habe die FFT Werte Verstärkt var v1 = this.Analyser1.peak ? FFT_Data[pt] / this.Analyser1.peak : 0;
v1*=Math.pow(10,10)
Bei mir kommt das
Spektrum_komisch.png
Trotz deiner Normalisierung.

Man kann auch das pow Weglassen und ChromaJS auf 0 bis 0.003 z.B einstellen dann kommt das selbe.
Ohne Fensterfunktion ist alles TOP

Spektrum_gut.png
 
Zuletzt bearbeitet:
Komisch ist das da ober und unterhalb des Tärger noch was ist und das dar nicht sein. Wenn man das Hann window raus nimmt ist das auch weg.
ja logisch, dann ist es ja auch ein reiner sin und keine überlagerung mehrerer


Ich möchte über 2 Slider noch Helligkeit und Kontrast mit einbringen um schwache Signal besser hervor heben zu können.
Da ich das noch nicht implementiert habe, habe ich das signal einfach via MAth.pow(10,10) verstärkt und da kommen Träger mit zum Vorschein die dürfen nicht sein. Ist das bei dir nicht so??
in deinem original schon, kein wunder, wenn du alles mit 10000000000 multiplizierst, kommt dir jedes staubkorn so groß wie die erde vor

Bei mir kommt das
Anhang anzeigen 4710
Trotz deiner Normalisierung.
weil du es wieder mit 10000000000 multiplizierst

Ohne Fensterfunktion ist alles TOP
auch mit, wir sind hier bei amplituden von 10 hoch -11 bis max. 10 hoch -7 im vergleich zu 0,03

- - - Aktualisiert - - -

auch mit, wir sind hier bei amplituden von 10 hoch -11 bis max. 10 hoch -7 im vergleich zu 0,03
nee, nicht mal 10^-14 bis 10^-11

- - - Aktualisiert - - -

ja logisch, dann ist es ja auch ein reiner sin und keine überlagerung mehrerer
und selbst bei dem sind vermutlich werte für andere frequenzen da, nur vermutlich noch viel viel kleiner, häng mal noch ein paar 0-en an deinen faktor drann, so daß du im bereich 10^-100 bist,
 
tsseh schrieb:
in deinem original schon, kein wunder, wenn du alles mit 10000000000 multiplizierst, kommt dir jedes staubkorn so groß wie die erde vor
AAAAAllllles klar ich mache es einfach nur zu "Laut".

Ok, dann muss mir überlegen wie ich das mit den Helligkeits und Kontrast slider hinbekomme.
sicherlich weißt Du drauf eine Antwort.

Ich stelle mir folgendes vor:
Ein User stellt ein er möchte von -120dB bis -10dB Darstellen (Lautstärke).
Danach wir eine linear gradient gerendert mit einer Skala von -120 bis -10
Dan kommen 2 Slider in spiel, Der Kontrast slider macht das gradient Schmaler, so das von -120 bis -50 db alle Single schwarz sind und nur die lauteren ab -50 bis 0 bekommen Farbe.
Der Helligkeitssilder verschiebt jetzt noch den bereich so das schwache peaks, die von -120 bis -50 db gehen Farbe bekommen, das hat aber den nachteil das peaks von -50 bis 0 alle zu Hell wären.

In Spektumlab sieht das so aus.
Silders.png
Das hat den vorteil das man an der Farbe erkenne kann wie Stark war den das Signal.

Das wohl einfachste wäre die FFT Werte nach dB bringen. Dann erst komme die Werte von den Slidern da zu. Man kann SpektrumLab vom Internet Remote steuern, daher weiß ich das die Slider werte von 0-255 gehen.

Also muss ich Chroma auf 0bis256 einstellen. Nur die FFT Values nach den User Eingestellten Dezibel bringen komme ich nicht zu rande.


tsseh schrieb:
, häng mal noch ein paar 0-en an deinen faktor drann, so daß du im bereich 10^-100 bist,
in der tat. Aber wie entstehen diese "pseudo" träger? Bei Oberwellen ist es ja so wen man die Amplitude zu laut mach wird der Sinus irgendwann zum Rechteck, dann hat man Oberwellen. So ist es zumindest in der Hardware. Aber das sind ja Unterwellen bei gleicher Amplitude, Produziert die FFT das?
 
Zuletzt bearbeitet:
AAAAAllllles klar ich mache es einfach nur zu "Laut".
naja, die frage ist ja schon mal, was ist das für ein signal?
wir hatten ja bisher quasi ein normiertes. muss das normiert sein, weil die audio libs das so brauchen? ist das überhaupt normiert?
dann brauchst du ja noch den normierungsfaktor mit dem du die fft werte mult. musst.

Ok, dann muss mir überlegen wie ich das mit den Helligkeits und Kontrast slider hinbekomme.
warum Helligkeits und Kontrast?

sicherlich weißt Du drauf eine Antwort.
ich hab keine ahnung, was du für signale hast und keine ahnung wie audio signale definiert sind.

Ich stelle mir folgendes vor:
Ein User stellt ein er möchte von -120dB bis -10dB Darstellen (Lautstärke).
was bedeutet das für dein ursprungssignal?
https://de.wikipedia.org/wiki/Bel_(Einheit)
wenn du rein nach definition gehst, ist dein db-wert = 10*log10(fft-amplitude) und deine fft-amplitude würde dem quadrat der echten amplitude entsprechen.(wobei deine amplitude bezogen auf eine referenz amplitude sind)
womit dann db-wert = 20*log10(echten amplitude)=10*log10(fft-amplitude)
das wird es aber nicht sein
gut, gilt also db-wert = 10*log10(echten amplitude) und echten amplitude = normierungsfaktor * fft-amplitude

Danach wir eine linear gradient gerendert mit einer Skala von -120 bis -10
Dan kommen 2 Slider in spiel, Der Kontrast slider macht das gradient Schmaler, so das von -120 bis -50 db alle Single schwarz sind und nur die lauteren ab -50 bis 0 bekommen Farbe.
Der Helligkeitssilder verschiebt jetzt noch den bereich so das schwache peaks, die von -120 bis -50 db gehen Farbe bekommen, das hat aber den nachteil das peaks von -50 bis 0 alle zu Hell wären.
warum jetzt -50? wenn du -120dB bis -10dB darstellen willst?

In Spektumlab sieht das so aus.
Anhang anzeigen 4712
Das hat den vorteil das man an der Farbe erkenne kann wie Stark war den das Signal.
das sieht für mich so aus, als ob dein Kontrast einfach die grenze ist, ab der werte auf 0 gesetzt werden.
also, will man werte im berich -120 bis -10 darstellen, musst du alles größer 10 nullen, und den bereich -120 bis -10 auf den "Chroma-bereich" 0 bis 1 normieren
was auch darüber gehen würde die limits in Chroma auf -120 und -10 zu setzen, wenn das geht.

Nur die FFT Values nach den User Eingestellten Dezibel bringen komme ich nicht zu rande.
mit 10*log10(fftwert) liegst du zumindestens nicht ganz daneben. vermutlich musst du noch einen normierungsfaktor einrechnen
also 10*log10(normierungsfaktor * fftwert)


in der tat. Aber wie entstehen diese "pseudo" träger?
ich sehe da keine "pseudo" träger, sondern ungenauigkeiten nahe 0
 
Zurück
Oben