staticvoid min_curve(float *c, float *c2){ int i; for(i=0;i<EHMER_MAX;i++)if(c2[i]<c[i])c[i]=c2[i];
} staticvoid max_curve(float *c, float *c2){ int i; for(i=0;i<EHMER_MAX;i++)if(c2[i]>c[i])c[i]=c2[i];
}
staticvoid attenuate_curve(float *c,float att){ int i; for(i=0;i<EHMER_MAX;i++)
c[i]+=att;
}
staticfloat ***setup_tone_curves(float curveatt_dB[P_BANDS],float binHz,int n, float center_boost, float center_decay_rate){ int i,j,k,m; float ath[EHMER_MAX]; float workc[P_BANDS][P_LEVELS][EHMER_MAX]; float athc[P_LEVELS][EHMER_MAX]; float *brute_buffer=alloca(n*sizeof(*brute_buffer));
float ***ret=_ogg_malloc(sizeof(*ret)*P_BANDS);
memset(workc,0,sizeof(workc));
for(i=0;i<P_BANDS;i++){ /* we add back in the ATH to avoid low level curves falling off to -infinityandunnecessarilycuttingoffhighlevelcurvesinthe
curve limiting (last step). */
/* A half-band's settings must be valid over the whole band, and
it's better to mask too little than too much */ int ath_offset=i*4; for(j=0;j<EHMER_MAX;j++){ float min=999.; for(k=0;k<4;k++) if(j+k+ath_offset<MAX_ATH){ if(min>ATH[j+k+ath_offset])min=ATH[j+k+ath_offset];
}else{ if(min>ATH[MAX_ATH-1])min=ATH[MAX_ATH-1];
}
ath[j]=min;
}
/* copy curves into working space, replicate the 50dB curve to 30
and 40, replicate the 100dB curve to 110 */ for(j=0;j<6;j++)
memcpy(workc[i][j+2],tonemasks[i][j],EHMER_MAX*sizeof(*tonemasks[i][j]));
memcpy(workc[i][0],tonemasks[i][0],EHMER_MAX*sizeof(*tonemasks[i][0]));
memcpy(workc[i][1],tonemasks[i][0],EHMER_MAX*sizeof(*tonemasks[i][0]));
/* normalize curves so the driving amplitude is 0dB */ /* make temp curves with the ATH overlayed */ for(j=0;j<P_LEVELS;j++){
attenuate_curve(workc[i][j],curveatt_dB[i]+100.-(j<2?2:j)*10.-P_LEVEL_0);
memcpy(athc[j],ath,EHMER_MAX*sizeof(**athc));
attenuate_curve(athc[j],+100.-j*10.f-P_LEVEL_0);
max_curve(athc[j],workc[i][j]);
}
for(i=0;i<P_BANDS;i++){ int hi_curve,lo_curve,bin;
ret[i]=_ogg_malloc(sizeof(**ret)*P_LEVELS);
/* low frequency curves are measured with greater resolution than theMDCT/FFTwillactuallygiveus;wewantthecurveapplied tothetonedatatobepessimisticandthusapplytheminimum maskingpossibleforagivenbin.Thatmeansthatasinglebin couldspanmorethanoneoctaveandthatthecurvewillbea compositeofmultipleoctaves.Italsomaymeanthatasingle binmayspan>aneighthofanoctaveandthattheeighth
octave values may also be composited. */
/* which octave curves will we be compositing? */
bin=floor(fromOC(i*.5)/binHz);
lo_curve= ceil(toOC(bin*binHz+1)*2);
hi_curve= floor(toOC((bin+1)*binHz)*2); if(lo_curve>i)lo_curve=i; if(lo_curve<0)lo_curve=0; if(hi_curve>=P_BANDS)hi_curve=P_BANDS-1;
/* render the curve into bins, then pull values back into curve. Thepointisthatanyinherentsubsamplingaliasingresultsin
a safe minimum */ for(k=lo_curve;k<=hi_curve;k++){ int l=0;
for(j=0;j<EHMER_MAX;j++){ int lo_bin= fromOC(j*.125+k*.5-2.0625)/binHz; int hi_bin= fromOC(j*.125+k*.5-1.9375)/binHz+1;
/* be equally paranoid about being valid up to next half ocatve */ if(i+1<P_BANDS){ int l=0;
k=i+1; for(j=0;j<EHMER_MAX;j++){ int lo_bin= fromOC(j*.125+i*.5-2.0625)/binHz; int hi_bin= fromOC(j*.125+i*.5-1.9375)/binHz+1;
/* set up rolling noise median */
p->noiseoffset=_ogg_malloc(P_NOISECURVES*sizeof(*p->noiseoffset)); for(i=0;i<P_NOISECURVES;i++)
p->noiseoffset[i]=_ogg_malloc(n*sizeof(**p->noiseoffset));
for(i=0;i<n;i++){ float halfoc=toOC((i+.5)*rate/(2.*n))*2.; int inthalfoc; float del;
if(halfoc<0)halfoc=0; if(halfoc>=P_BANDS-1)halfoc=P_BANDS-1;
inthalfoc=(int)halfoc; /*If we hit the P_BANDS-1 clamp above, inthalfoc+1 will be out of bounds, eventhoughitwillhaveaninterpolationweightof0.
Shift the interval so we don't read past the end of the array.*/ if(inthalfoc>=P_BANDS-2)inthalfoc=P_BANDS-2;
del=halfoc-inthalfoc;
/* octave/(8*eighth_octave_lines) x scale and dB y scale */ staticvoid seed_curve(float *seed, constfloat **curves, float amp, int oc, int n, int linesper,float dBoffset){ int i,post1; int seedptr; constfloat *posts,*curve;
int choice=(int)((amp+dBoffset-P_LEVEL_0)*.1f);
choice=max(choice,0);
choice=min(choice,P_LEVELS-1);
posts=curves[choice];
curve=posts+2;
post1=(int)posts[1];
seedptr=oc+(posts[0]-EHMER_OFFSET)*linesper-(linesper>>1);
staticvoid seed_chase(float *seeds, int linesper, long n){ long *posstack=alloca(n*sizeof(*posstack)); float *ampstack=alloca(n*sizeof(*ampstack)); long stack=0; long pos=0; long i;
for(i=0;i<n;i++){ if(stack<2){
posstack[stack]=i;
ampstack[stack++]=seeds[i];
}else{ while(1){ if(seeds[i]<ampstack[stack-1]){
posstack[stack]=i;
ampstack[stack++]=seeds[i]; break;
}else{ if(i<posstack[stack-1]+linesper){ if(stack>1 && ampstack[stack-1]<=ampstack[stack-2] &&
i<posstack[stack-2]+linesper){ /* we completely overlap, making stack-1 irrelevant. pop it */
stack--; continue;
}
}
posstack[stack]=i;
ampstack[stack++]=seeds[i]; break;
}
}
}
}
/* the stack now contains only the positions that are relevant. Scan
'em straight through */
for(i=0;i<stack;i++){ long endpos; if(i<stack-1 && ampstack[i+1]>ampstack[i]){
endpos=posstack[i+1];
}else{
endpos=posstack[i]+linesper+1; /* +1 is important, else bin 0 is
discarded in short frames */
} if(endpos>n)endpos=n; for(;pos<endpos;pos++)
seeds[pos]=ampstack[i];
}
/* there. Linear time. I now remember this was on a problem set I
had in Grad Skool... I didn't solve it at the time ;-) */
}
/* bleaugh, this is more complicated than it needs to be */ #include<stdio.h> staticvoid max_seeds(vorbis_look_psy *p, float *seed, float *flr){ long n=p->total_octave_lines; int linesper=p->eighth_octave_lines; long linpos=0; long pos;
A = tY * tXX - tX * tXY;
B = tN * tXY - tX * tY;
D = tN * tXX - tX * tX;
R = (A + x * B) / D;
if (R - offset < noise[i]) noise[i] = R - offset;
} for ( ; i < n; i++, x += 1.f) {
R = (A + x * B) / D; if (R - offset < noise[i]) noise[i] = R - offset;
}
}
if(offset_select == 1) {
coeffi = -17.2; /* coeffi is a -17.2dB threshold */
val = val - logmdct[i]; /* val == mdct line value relative to floor in dB */
if(val > coeffi){ /* mdct value is > -17.2 dB below floor */
/* this is for per-channel noise normalization */ staticint apsort(constvoid *a, constvoid *b){ float f1=**(float**)a; float f2=**(float**)b; return (f1<f2)-(f1>f2);
}
staticvoid flag_lossless(int limit, float prepoint, float postpoint, float *mdct, float *floor, int *flag, int i, int jn){ int j; for(j=0;j<jn;j++){ float point = j>=limit-i ? postpoint : prepoint; float r = fabs(mdct[j])/floor[j]; if(r<point)
flag[j]=0; else
flag[j]=1;
}
}
/* Overload/Side effect: On input, the *q vector holds either the quantizedenergy(forelementswiththeflagset)ortheabsolute valuesofthe*rvector(forelementswithflagunset).Onoutput,
*q holds the quantized energy for all elements */ staticfloat noise_normalize(vorbis_look_psy *p, int limit, float *r, float *q, float *f, int *flags, float acc, int i, int n, int *out){
vorbis_info_psy *vi=p->vi; float **sort = alloca(n*sizeof(*sort)); int j,count=0; int start = (vi->normal_p ? vi->normal_start-i : n); if(start>n)start=n;
/* force classic behavior where only energy in the current band is considered */
acc=0.f;
/* still responsible for populating *out where noise norm not in
effect. There's no need to [re]populate *q in these areas */ for(j=0;j<start;j++){ if(!flags || !flags[j]){ /* lossless coupling already quantized. Don'ttouch;requantizingbasedon
energy would be incorrect. */ float ve = q[j]/f[j]; if(r[j]<0)
out[j] = -rint(sqrt(ve)); else
out[j] = rint(sqrt(ve));
}
}
/* sort magnitudes for noise norm portion of partition */ for(;j<n;j++){ if(!flags || !flags[j]){ /* can't noise norm elements that have alreadybeenloslesslycoupled;wecan
only account for their energy error */ float ve = q[j]/f[j]; /* Despite all the new, more capable coupling code, for now we implementnoisenormasithasbeenuptothispoint.Only considerpromotionstounitmagnitudefrom0.Inaddition
the only energy error counted is quantizations to zero. */ /* also-- the original point code only applied noise norm at > pointlimit */ if(ve<.25f && (!flags || j>=limit-i)){
acc += ve;
sort[count++]=q+j; /* q is fabs(r) for unflagged element */
}else{ /* For now: no acc adjustment for nonzero quantization. populate *out and q as this value is final. */ if(r[j]<0)
out[j] = -rint(sqrt(ve)); else
out[j] = rint(sqrt(ve));
q[j] = out[j]*out[j]*f[j];
}
}/* else{ again,noenergyadjustmentforerrorinnonzeroquant--fornow
}*/
}
if(count){ /* noise norm to do */
qsort(sort,count,sizeof(*sort),apsort); for(j=0;j<count;j++){ int k=sort[j]-q; if(acc>=vi->normal_thresh){
out[k]=unitnorm(r[k]);
acc-=1.f;
q[k]=f[k];
}else{
out[k]=0;
q[k]=0.f;
}
}
}
return acc;
}
/* Noise normalization, quantization and coupling are not wholly
seperable processes in depth>1 coupling. */ void _vp_couple_quantize_normalize(int blobno,
vorbis_info_psy_global *g,
vorbis_look_psy *p,
vorbis_info_mapping0 *vi, float **mdct, int **iwork, int *nonzero, int sliding_lowpass, int ch){
int i; int n = p->n; int partition=(p->vi->normal_p ? p->vi->normal_partition : 16); int limit = g->coupling_pointlimit[p->vi->blockflag][blobno]; float prepoint=stereo_threshholds[g->coupling_prepointamp[blobno]]; float postpoint=stereo_threshholds[g->coupling_postpointamp[blobno]]; #if0 float de=0.1*p->m_val; /* a blend of the AoTuV M2 and M3 code here and below */ #endif
/* mdct is our raw mdct output, floor not removed. */ /* inout passes in the ifloor, passes back quantized result */
/* unquantized energy (negative indicates amplitude has negative sign) */ float **raw = alloca(ch*sizeof(*raw));
/* dual pupose; quantized energy (if flag set), othersize fabs(raw) */ float **quant = alloca(ch*sizeof(*quant));
/* floor energy */ float **floor = alloca(ch*sizeof(*floor));
/* flags indicating raw/quantized status of elements in raw vector */ int **flag = alloca(ch*sizeof(*flag));
/* non-zero flag working vector */ int *nz = alloca(ch*sizeof(*nz));
/* energy surplus/defecit tracking */ float *acc = alloca((ch+vi->coupling_steps)*sizeof(*acc));
/* The threshold of a stereo is changed with the size of n */ if(n > 1000)
postpoint=stereo_threshholds_limited[g->coupling_postpointamp[blobno]];
for(i=0;i<vi->coupling_steps;i++){ /* make sure coupling a zero and a nonzero channel results in two
nonzero channels. */ if(nonzero[vi->coupling_mag[i]] ||
nonzero[vi->coupling_ang[i]]){
nonzero[vi->coupling_mag[i]]=1;
nonzero[vi->coupling_ang[i]]=1;
}
}
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.18 Sekunden
(vorverarbeitet am 2026-08-25)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.