📄 resample.c
字号:
memcpy( newp+(di*4), p+(si*4), 4 ); idx += (double)(global.playback_rate/100.0); si = (long)idx; di++; } return di;}#endifstatic int guess_endianess(p, p2, SamplesToDo) UINT4 *p; short *p2; unsigned SamplesToDo;{ /* analyse samples */ int vote_for_little = 0; int vote_for_big = 0; int total_votes; while (((UINT4 *)p2 - p) + (unsigned) 1 < SamplesToDo) { unsigned char *p3 = (unsigned char *)p2;#if MY_LITTLE_ENDIAN == 1 int diff_lowl = *(p2+0) - *(p2+2); int diff_lowr = *(p2+1) - *(p2+3); int diff_bigl = ((*(p3 ) << 8) + *(p3+1)) - ((*(p3+4) << 8) + *(p3+5)); int diff_bigr = ((*(p3+2) << 8) + *(p3+3)) - ((*(p3+6) << 8) + *(p3+7));#else int diff_lowl = ((*(p3+1) << 8) + *(p3 )) - ((*(p3+5) << 8) + *(p3+4)); int diff_lowr = ((*(p3+3) << 8) + *(p3+2)) - ((*(p3+7) << 8) + *(p3+6)); int diff_bigl = *(p2+0) - *(p2+2); int diff_bigr = *(p2+1) - *(p2+3);#endif if ((abs(diff_lowl) + abs(diff_lowr)) < (abs(diff_bigl) + abs(diff_bigr))) { vote_for_little++; } else { if ((abs(diff_lowl) + abs(diff_lowr)) > (abs(diff_bigl) + abs(diff_bigr))) { vote_for_big++; } } p2 += 2; }#ifdef DEBUG_VOTE_ENDIANESS if (global.quiet != 1) fprintf(stderr, "votes for little: %4d, votes for big: %4d\n", vote_for_little, vote_for_big);#endif total_votes = vote_for_big + vote_for_little; if (total_votes < 3 || abs(vote_for_big - vote_for_little) < total_votes/3) { return -1; } else { if (vote_for_big > vote_for_little) return 1; else return 0; }}int jitterShift = 0; unsigned char *synchronize(p, SamplesToDo, TotSamplesDone) UINT4 *p; unsigned SamplesToDo; unsigned TotSamplesDone;{ static int jitter = 0; char *pSrc; /* start of cdrom buffer */ /* if endianess is unknown, guess endianess based on differences between succesive samples. If endianess is correct, the differences are smaller than with the opposite byte order. */ if ((*in_lendian) < 0) { short *p2 = (short *)p; /* skip constant samples */ while ((((UINT4 *)p2 - p) + (unsigned) 1 < SamplesToDo) && *p2 == *(p2+2)) p2++; if (((UINT4 *)p2 - p) + (unsigned) 1 < SamplesToDo) { switch (guess_endianess(p, p2, SamplesToDo)) { case -1: break; case 1: (*in_lendian) = 0;#if 0 if (global.quiet != 1) fprintf(stderr, "big endian detected\n");#endif break; case 0: (*in_lendian) = 1;#if 0 if (global.quiet != 1) fprintf(stderr, "little endian detected\n");#endif break; } } } /* ENDIAN ISSUES: * the individual endianess of cdrom/cd-writer, cpu, * sound card and audio output format need a careful treatment. * * For possible sample processing (rate conversion) we need * the samples in cpu byte order. This is the first conversion. * * After processing it depends on the endianness of the output * format, whether a second conversion is needed. * */ if (global.need_hostorder && (*in_lendian) != MY_LITTLE_ENDIAN) { /* change endianess of delivered samples to native cpu order */ change_endianness(p, SamplesToDo); } /* synchronisation code */ if (TotSamplesDone != 0 && global.overlap != 0 && SamplesToDo > CD_FRAMESAMPLES) { pSrc = (char *) sync_buffers((unsigned char *)p); if (!pSrc ) { return NULL; } if (pSrc) { jitter = ((unsigned char *)pSrc - (((unsigned char *)p) + global.overlap*CD_FRAMESIZE_RAW))/4; jitterShift += jitter; SamplesToDo -= jitter + global.overlap*CD_FRAMESAMPLES;#if 0 fprintf(stderr, "Length: pre %d, diff1 %ld, diff2 %ld, min %ld\n", SamplesToDo, (TotSamplesWanted - TotSamplesDone), SamplesNeeded((TotSamplesWanted - TotSamplesDone), undersampling), min(SamplesToDo, SamplesNeeded((TotSamplesWanted - TotSamplesDone), undersampling)));#endif } } else { pSrc = ( char * ) p; } return (unsigned char *) pSrc;}/* convert cdda data to required output format * sync code for unreliable cdroms included * */long SaveBuffer (p, SamplesToDo, TotSamplesDone) UINT4 *p; unsigned long SamplesToDo; unsigned long *TotSamplesDone;{ UINT4 *pSrc; /* start of cdrom buffer */ UINT4 *pSrcStop; /* end of cdrom buffer */ /* in case of different endianness between host and output format, copy in a seperate buffer and modify the local copy */ if ( ((!global.need_hostorder && global.need_big_endian == (*in_lendian)) || (global.need_hostorder && global.need_big_endian != MY_BIG_ENDIAN)) && global.OutSampleSize > 1) { static UINT4 *localoutputbuffer; if (localoutputbuffer == NULL) { localoutputbuffer = (UINT4 *) malloc(global.nsectors*CD_FRAMESIZE_RAW); if (localoutputbuffer == NULL) { perror("cannot allocate local buffer"); return 1; } } memcpy(localoutputbuffer, p, SamplesToDo*4); p = localoutputbuffer; } pSrc = p; pDst = (unsigned char *) p; pStart = ( unsigned char * ) pSrc; pSrcStop = pSrc + SamplesToDo; /* code for subsampling and output stage */ if (global.ismono && global.findmono) { short *pmm; for (pmm = (short *)pStart; (UINT4 *) pmm < pSrcStop; pmm += 2) { if (*pmm != *(pmm+1)) { global.ismono = 0; break; } } } /* optimize the case of no conversion */ if (1 && undersampling == 1 && samples_to_do == 1 && global.channels == 2 && global.OutSampleSize == 2 && Halved == 0) { /* output format is the original cdda format -> * just forward the buffer */ if ( waitforsignal != 0 && any_signal == 0) { int *myptr = (int *)pStart; while ((UINT4 *)myptr < pSrcStop && *myptr == 0) myptr++; pStart = (unsigned char *) myptr; /* scan for first signal */ if ( (UINT4 *)pStart != pSrcStop ) { /* first non null amplitude is found in buffer */ any_signal = 1; } } pDst = (unsigned char *) pSrcStop; /* set pDst to end */ if (global.deemphasize) { /* this implements an attenuation treble shelving filter to undo the effect of pre-emphasis. The filter is of a recursive first order */ static short lastin[2] = { 0, 0 }; static double lastout[2] = { 0.0, 0.0 }; short *pmm; /* Here is the gnuplot file for the frequency response of the deemphasis. The error is below +-0.1dB# first define the ideal filter. We use the tenfold sampling frequency.T=1./441000.OmegaU=1./15E-6OmegaL=15./50.*OmegaUV0=OmegaL/OmegaUH0=V0-1.B=V0*tan(OmegaU*T/2.)# the coefficients followa1=(B - 1.)/(B + 1.)b0=(1.0 + (1.0 - a1) * H0/2.)b1=(a1 + (a1 - 1.0) * H0/2.)# helper variablesD=b1/b0o=2*pi*TH2(f)=b0*sqrt((1+2*cos(f*o)*D+D*D)/(1+2*cos(f*o)*a1+a1*a1))# now approximate the ideal curve with a fitted one for sampling frequency# of 44100 Hz.T2=1./44100.V02=0.3365OmegaU2=1./19E-6B2=V02*tan(OmegaU2*T2/2.)# the coefficients followa12=(B2 - 1.)/(B2 + 1.)b02=(1.0 + (1.0 - a12) * (V02-1.)/2.)b12=(a12 + (a12 - 1.0) * (V02-1.)/2.)# helper variablesD2=b12/b02o2=2*pi*T2H(f)=b02*sqrt((1+2*cos(f*o2)*D2+D2*D2)/(1+2*cos(f*o2)*a12+a12*a12))# plot best, real, ideal, level with halved attenuation,# level at full attentuation, 10fold magnified errorset logscale xset grid xtics ytics mxtics myticsplot [f=1000:20000] [-12:2] 20*log10(H(f)),20*log10(H2(f)), 20*log10(OmegaL/(2*pi*f)), 0.5*20*log10(V0), 20*log10(V0), 200*log10(H(f)/H2(f))pause -1 "Hit return to continue" */#ifdef TEST#define V0 0.3365#define OMEGAG (1./19e-6)#define T (1./44100.)#define H0 (V0-1.)#define B (V0*tan((OMEGAG * T)/2.0))#define a1 ((B - 1.)/(B + 1.))#define b0 (1.0 + (1.0 - a1) * H0/2.0)#define b1 (a1 + (a1 - 1.0) * H0/2.0)#else#define a1 -0.62786881719628784282#define b0 0.45995451989513153057#define b1 -0.08782333709141937339#endif for (pmm = (short *)pStart; pmm < (short *)pDst;) { lastout[0] = *pmm * b0 + lastin[0] * b1 - lastout[0] * a1; lastin[0] = *pmm; *pmm++ = lastout[0] > 0.0 ? lastout[0] + 0.5 : lastout[0] - 0.5; lastout[1] = *pmm * b0 + lastin[1] * b1 - lastout[1] * a1; lastin[1] = *pmm; *pmm++ = lastout[1] > 0.0 ? lastout[1] + 0.5 : lastout[1] - 0.5; } } if (global.swapchannels == 1) { swap_channels((UINT4 *)pStart, SamplesToDo); } if (global.findminmax) { short *pmm; for (pmm = (short *)pStart; pmm < (short *)pDst; pmm++) { if (*pmm < global.minamp[1]) global.minamp[1] = *pmm; if (*pmm > global.maxamp[1]) global.maxamp[1] = *pmm; pmm++; if (*pmm < global.minamp[0]) global.minamp[0] = *pmm; if (*pmm > global.maxamp[0]) global.maxamp[0] = *pmm; } } } else {#define none_missing 0#define one_missing 1#define two_missing 2#define collecting 3 static int sample_state = collecting; static int Toggle_on = 0; if (global.channels == 2 && global.swapchannels == 1) { swap_channels((UINT4 *)pStart, SamplesToDo); } /* conversion required */ while ( pSrc < pSrcStop ) { long l,r; long iSamples_left = (pSrcStop - pSrc) / sizeof(short) / 2; short *myptr = (short *) pSrc; /* LSB l, MSB l */ l = *myptr++; /* left channel */ r = *myptr++; /* right channel */ pSrc = (UINT4 *) myptr; switch (sample_state) { case two_missing:two__missing: ls2 += l; rs2 += r; if (undersampling > 1) { ls3 += l; rs3 += r; } sample_state = one_missing; break; case one_missing: auxl = l; auxr = r; ls3 += l; rs3 += r; sample_state = none_missing; /* FALLTHROUGH */none__missing: case none_missing: /* Filtered samples are complete. Now interpolate and scale. */ if (Halved != 0 && Toggle_on == 0) { lsum = interpolate(lsum, ls2, ls3)/(int) undersampling; rsum = interpolate(rsum, rs2, rs3)/(int) undersampling; } else { lsum /= (int) undersampling; rsum /= (int) undersampling; } emit_sample(lsum, rsum, global.channels); /* reload counter */ samples_to_do = undersampling - 1; lsum = auxl; rsum = auxr; /* reset sample register */ auxl = ls2 = ls3 = 0; auxr = rs2 = rs3 = 0; Toggle_on ^= 1; sample_state = collecting; break; case collecting: if ( samples_to_do > 0) { samples_to_do--; if (Halved != 0 && Toggle_on == 0) { /* Divider x.5 : we need data for quadratic interpolation */ iSamples_left--; lsum += l; rsum += r; if ( samples_to_do < undersampling - 1) { ls2 += l; rs2 += r; } if ( samples_to_do < undersampling - 2) { ls3 += l; rs3 += r; } } else { /* integral divider */ lsum += l; rsum += r; iSamples_left--; } } else { if (Halved != 0 && Toggle_on == 0) { sample_state = two_missing; goto two__missing; } else { auxl = l; auxr = r; sample_state = none_missing; goto none__missing; } } break; } /* switch state */ } /* while */ /* flush_buffer */ if ((samples_to_do == 0 && Halved == 0)) { if (Halved != 0 && Toggle_on == 0) { lsum = interpolate(lsum, ls2, ls3)/(int) undersampling; rsum = interpolate(rsum, rs2, rs3)/(int) undersampling; } else { lsum /= (int) undersampling; rsum /= (int) undersampling; } emit_sample(lsum, rsum, global.channels); /* reload counter */ samples_to_do = undersampling; /* reset sample register */ lsum = auxl = ls2 = ls3 = 0; rsum = auxr = rs2 = rs3 = 0; Toggle_on ^= 1; sample_state = collecting; } } /* if optimize else */ if ( waitforsignal == 0 ) pStart = (unsigned char *)p; else if (any_signal != 0) global.SkippedSamples += ((UINT4 *)pStart - p); else global.SkippedSamples += (pSrcStop - p); if ( waitforsignal == 0 || any_signal != 0) { int retval = 0; unsigned outlen; assert(pDst >= pStart); outlen = (size_t) (pDst - pStart); if (outlen <= 0) return 0;#ifdef ECHO_TO_SOUNDCARD /* this assumes the soundcard needs samples in native cpu byte order */ if (global.echo != 0) { static unsigned char *newp; unsigned newlen; newlen = (100*(outlen/4))/global.playback_rate; newlen = (newlen*4); if ( (newp != NULL) || (newp = (unsigned char *) malloc( 2*global.nsectors*CD_FRAMESIZE_RAW+32 )) ) { newlen = 4*ReSampleBuffer( pStart, newp, outlen/4 ); write_snd_device((char *)newp, newlen); } }#endif if ( global.no_file != 0 ) { *TotSamplesDone += SamplesToDo; return 0; } if ( (!global.need_hostorder && global.need_big_endian == (*in_lendian)) || (global.need_hostorder && global.need_big_endian != MY_BIG_ENDIAN)) { if ( global.OutSampleSize > 1) { /* change endianness from input sample or native cpu order to required output endianness */ change_endianness((UINT4 *)pStart, outlen/4); } } if ((unsigned)(retval = write ( global.audio, pStart, outlen )) == outlen) { *TotSamplesDone += SamplesToDo; return 0; } else { fprintf(stderr, "write(audio, 0x%p, %u) = %d\n",pStart,outlen,retval); perror("Probably disk space exhausted"); return 1; } } else return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -