[KLEMM_42] Neue Bandweitenberechnung für das Kodieren mit Lame. Für <= 128 kbps wird eine Mindestanzahl von Bits pro spektraler Linie gefordert (die auch etwas von der bitrate abhängig ist), oberhalb von 128 kbps wird die zusätzliche Bandbreite zu einem bestimmnten Teil in die NMR und zum anderen in die Bandbreite gesteckt. Ist romanmäßig in der Quelle beschrieben. Man braucht etwa 2.2 bit/Spektrallinie für gute Qualität, unterhalb von 1.8 bit fängt deutliches Twickling an. Tests mit 160 kbps und Casta ergeben einen besseren Klang mit einer Wahrscheinlichkeit >99.95% mit einer Rate-Entropie von ca. 0,5 bit pro Versuch. Für 160 kbps gibt es dann noch KLEMM_12, welches nicht abrupt oberhalb von 128 kbps auf Stereo umschaltet, sondern langsam die Schaltschwelle für LR und MS verschiebt. Ergibt einen besseren Klang mit einer Wahrscheinlichkeit >99.995% mit einer Rateentropie von ca. 1,0 bit pro Versuch. Aber an dieser Schaltung will ich noch etwas mehr basteln. Zum einen ist noch ein Fehler in der PE von MS, zum anderen soll die Schaltschwelle von der Vorgeschichte abhängen: LR => MS: Mindestbitersparnis von MS gegenüber LR: 112 kbps: 1.25 kbps 128 kbps: 4 kbps 160 kbps: 10 kbps 192 kbps: 24 kbps 224 kbps: 56 kbps 256 kbps: immer Stereo MS => LR: Mehrverbrauch von MS gegenüber LR: 112 kbps: 1.25 kbps 128 kbps: 4 kbps 160 kbps: -2 kbps (Stabiltätspunkt liegt bei LR) 192 kbps: -8 kbps (Stabiltätspunkt liegt bei LR) 224 kbps: -24 kbps (Stabiltätspunkt liegt bei LR) 256 kbps: immer Stereo Verwendung findet allerdings die modifizierte Klemmsche Entropie, die bei MS-Kodierung auch die Nichtlinearität der Kodierung berücksichtigt, die zu sehr großen Strafpunkten bei sehr unterschiedlichen Pegeln in beiden Kanälen führt. Das ist einer der wesentlichen Punkte, die bei MS bis jetzt nicht berücksichtigt werden. Ich habe mal den etwas falscheren Quantisierer benutzt, der im Quantisierungsraum rundet statt im Quellraum. Ergebnis ist aber das gleiche. Praxisfremde pathologische Beispiele (Skalierung fsb L und R identisch=1): Quelle quantisiert dekodiert Fehler L R qM qS L' R' dL dR 45.45 0.01 | 14 13 | 45.474 2.245 | -0.024 -2.235 59.60 9.59 | 18 15 | 59.515 7.198 | 0.085 2.392 66.72 2.46 | 18 18 | 66.713 0.000 | 0.007 2.460 66.72 2.48 | 19 17 | 66.759 4.941 | -0.039 -2.461 71.98 12.57 | 22 17 | 74.498 12.681 | -2.518 -0.111 76.87 7.67 | 21 19 | 76.818 5.118 | 0.052 2.552 76.87 7.68 | 22 18 | 76.946 10.233 | -0.076 -2.553 97.99 8.16 | 26 22 | 98.054 10.875 | -0.064 -2.715 103.39 2.76 | 26 24 | 103.416 5.513 | -0.026 -2.753 114.55 2.84 | 28 26 | 114.586 5.657 | -0.036 -2.817 131.90 8.78 | 31 29 | 131.861 5.859 | 0.039 2.921 131.90 8.79 | 32 28 | 131.959 11.716 | -0.059 -2.926 1003.67 9.73 | 138 137 | 1003.660 4.866 | 0.010 4.864 1052.62 9.84 | 143 142 | 1052.614 4.924 | 0.006 4.916 Zum einen wäre es sinnvoll, eine PE(klemm) einzuführen, die das berück­ sichtigt. Zum anderen wäre ein Quantisierer, der beide Kanäle (M und S) gemeinsam kodiert, sinnvoll. Beim zweiteren bin ich mir ziemlich sicher, daß es FhG so macht. Die scheinen das nicht nur zwischen den Kanälen zu machen, sondern bei der Quantisierung auch die des vorherigen Granuls zu berücksichtigen. Die Fehler als |x_quant-x_orig| zu zählen, ist nicht der Weisheit letzter Schluß. Ansonsten wäre jede geringe Klangänderung fatal. Aber was man vermeiden sollte, ist, wildes Auf- und Abrunden bei ungünstigen Werten. Und das macht FhG (FhG verschmiert lieber Klänge als ein flatterndes Geräusch zu erzeugen). Mit dem neuen abx kann man das sich schön anhören. Vorherige Granule berücksichtigen (0.25 sind ein ITF = isolated tuning factor): int intelli_quant ( const double current_value, const double previous_value, const int previous_quant ) { const int current_quant = quant ( current_value ); switch ( current_quant - previous_quant ) { case +1: if ( (current_value - previous_value) < 0.25 * (dequant(current_quant) - dequant(previous_quant)) ) if (current_value < dequant(current_quant)) return previous_quant; return current_quant; case -1: if ( (current_value - previous_value) > 0.25 * (dequant(current_quant) - dequant(previous_quant)) ) if (current_value > dequant(current_quant)) return previous_quant; return current_quant; default: case 0: return current_quant; } } Ähnliches ist im MS Quantisierungfall möglich: double intelli_quant_ms ( const double left, /* voltage */ const double right, const double ath_left, /* power */ const double ath_right, int* const ret_mid, int* const ret_side ) { int quant_mid = quant (( left + right ) * sqrt (0.5)); int quant_side = quant (( left - right ) * sqrt (0.5)); int i; int j; double minerr = 1.e37; for ( i = -1; i <= +1; i++ ) for ( j = -1; j <= +1; j++ ) { double left_dec = (dequant(quant_mid+i) + dequant(quant_side+j)) * sqrt(0.5); double right_dec = (dequant(quant_mid+i) - dequant(quant_side+j)) * sqrt(0.5); double left_err = (left_dec - left ) * (left_dec - left ) / ath_left ; double right_err = (right_dec - right) * (right_dec - right) / ath_right; double err = left_err + right_err; if ( err < minerr ) { *ret_mid = quant_mid + i; *ret_side = quant_side + j; minerr = err; } } return minerr; } Das ganze laufzeitzuoptimieren (auf einfachere A&W abzuschätzen, welche von den 9 Fällen überhaupt sinnvoll sind), ist eine andere Angelegenheit. Etwas aufwendiger wird das ganze, wenn man intelli_quant_ms() und intelli_quant() kombinieren will. -- Frank Klemm