⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 offsetcalculator.java

📁 Java version of ABC/HR comparator v0.5. by schnofler. Runs on Sun JRE 1.5 or later
💻 JAVA
字号:
package abchr.audio;

import abchr.crypto.Util;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.UnsupportedAudioFileException;
import java.io.IOException;

public class OffsetCalculator {
	private static final int SAMPLE_POINTS=400;
	private static final int MAX_OFFSET=400;
	private static final int WINDOW_SIZE=2000;
	private static final int BUFFER_LENGTH=MAX_OFFSET+WINDOW_SIZE+10;

	public static char[] resample(char[] buffer,int length) {
		if(buffer.length==length){return buffer;}
		char[] result=new char[length];
		if(length<buffer.length) {
			for(int i=0;i<length;i++) {
				result[i]=buffer[(int)(((long)i)*buffer.length/length)];
			}
		}
		return result;
	}

	private static int calcOffset(char[] a,char[] b,int length) {
		int maxPossibleOffset=(int)(length*(MAX_OFFSET/(double)BUFFER_LENGTH));
		int window=(int)(length*(WINDOW_SIZE/(double)BUFFER_LENGTH));
		long max=0;
		int maxOffset=0;
		long product;
		int skip=window/SAMPLE_POINTS;
		for(int offset=0;offset<maxPossibleOffset;offset++) {
			product=0;
			for(int j=0,k=offset;j<window;j+=skip,k+=skip) {
				product+=(a[j]-32768)*(b[k]-32768);
			}
			if(product>max) {
				maxOffset=offset;
				max=product;
			}
			product=0;
			for(int j=0,k=offset;j<window;j+=skip,k+=skip) {
				product+=(a[k]-32768)*(b[j]-32768);
			}
			if(product>max) {
				maxOffset=-offset;
				max=product;
			}
		}
		return maxOffset;
	}

	public static float calcVolumeDifference(char[] a,char[] b,int length,int offset) {
		int window=length-Math.abs(offset)-10;
		long ssqa=0,ssqb=0;
		if(offset>0) {
			for(int i=0;i<window;i++) {
				ssqa+=(a[i]-32768)*(a[i]-32768);
			}
			for(int i=offset;i<offset+window;i++) {
				ssqb+=(b[i]-32768)*(b[i]-32768);
			}
		} else {
			for(int i=-offset;i<window-offset;i++) {
				ssqa+=(a[i]-32768)*(a[i]-32768);
			}
			for(int i=0;i<window;i++) {
				ssqb+=(b[i]-32768)*(b[i]-32768);
			}
		}
		double scale=Math.sqrt(ssqa/(double)ssqb);
		//System.out.println("scale="+scale);
		float gain=(float)(20*Math.log(scale)/Math.log(10));
		//System.out.println("gain="+gain);
		return gain;
	}

	private static char[] getSamples(Sample sample) throws IOException,UnsupportedAudioFileException {
		AudioInputStream stream=sample.getStream();
		AudioFormat format=stream.getFormat();
		if(format.getSampleSizeInBits()!=16) {
			throw new UnsupportedAudioFileException("Only 16bit files are supported for offset correction.");
		}
		stream.skip(3*((int)format.getFrameRate())*format.getFrameSize());
		byte[] temp=new byte[(int)(((int)format.getFrameRate())*format.getFrameSize()*(BUFFER_LENGTH)/1000.0d)];
		stream.read(temp);
		stream.close();
		char[] buffer=Util.bytesToChars(temp,format.isBigEndian());
		if(format.getChannels()!=1 && format.getChannels()!=2) {
			throw new UnsupportedAudioFileException("Number of channels invalid.");
		}
		if(format.getChannels()==2) {
			for(int i=0;i<buffer.length/2;i++) {
				buffer[i]=(char)((buffer[2*i]+buffer[2*i+1])/2);
			}
			char[] newBuffer=new char[buffer.length/2];
			System.arraycopy(buffer,0,newBuffer,0,buffer.length/2);
			buffer=newBuffer;
		}
		return buffer;
	}

	public static void configureOffsets(Sample[] files) throws IOException {
		final int n=files.length;
		char[][] samples=new char[n][];
		for(int i=0;i<n;i++) {
			try {
				samples[i]=getSamples(files[i]);
			} catch(Exception e) {
				throw new IOException("Could not open file "+files[i]);
			}
		}
		int minLength=equalizeSampleRate(samples);
		int[] results=new int[n];
		int minOffset=0;
		for(int i=1;i<n;i++) {
			results[i]=(int)Math.round((calcOffset(samples[0],samples[i],minLength)*BUFFER_LENGTH)/(double)minLength);
			//System.out.println("result["+i+"]="+results[i]);
			if(results[i]<minOffset){minOffset=results[i];}
		}
		if(minOffset<0) {
			for(int i=0;i<n;i++) {
				results[i]=results[i]-minOffset;
				//System.out.println("results["+i+"]="+results[i]);
			}
		}
		for(int i=0;i<n;i++) {
			samples[i]=null;
			SampleOffset.setOffset(files[i],results[i]);
		}
		samples=null;
	}

	private static int equalizeSampleRate(char[][] samples) {
		final int n=samples.length;
		int minLength=100000;
		for(int i=0;i<n;i++) {
			if(samples[i].length<minLength){minLength=samples[i].length;}
		}
		//System.out.println("minSampleRate="+minSampleRate);
		for(int i=0;i<n;i++) {
			samples[i]=resample(samples[i],minLength);
		}
		return minLength;
	}

	public static void configureOffset(Sample a,Sample b) throws IOException,UnsupportedAudioFileException {
		char[] aSamples=getSamples(a);
		char[] bSamples=getSamples(b);
		int minLength=aSamples.length<bSamples.length?aSamples.length:bSamples.length;
		aSamples=resample(aSamples,minLength);
		bSamples=resample(bSamples,minLength);
		int offset=calcOffset(aSamples,bSamples,minLength);
		offset=(int)Math.round((offset*BUFFER_LENGTH)/(double)minLength);
		//System.out.println("offset="+offset);
		if(offset>0){SampleOffset.setOffset(b,offset);}else{SampleOffset.setOffset(a,-offset);}
	}

	public static void configureGain(Sample a,Sample b) throws IOException,UnsupportedAudioFileException {
		float gain=0;
		gain=calcVolumeDifference(a,b);
		if(gain<=0){SampleGain.setGain(b,gain);}else{SampleGain.setGain(a,-gain);}
	}

	// buffer length will be 2^VOL_CORR_BUFFER_LENGTH
	private static final int VOL_CORR_BUFFER_LENGTH=7;
	// in seconds
	private static final int VOL_CORR_MAX_WINDOW=60;

	private static long calcMSMono(char[] buffer,int offset,int length) {
		if(length<=32) {
			long squareSum=0;
			for(int i=offset;i<offset+length;i++) {
				squareSum+=(buffer[i]-32768)*(buffer[i]-32768);
			}
			return squareSum >> 5;
		} else {
			int newLength=length>>1;
			return (calcMSMono(buffer,offset,newLength)+calcMSMono(buffer,offset+newLength,newLength))>>1;
		}
	}

	// maxLength can be used to limit the maximum window size (in seconds) that is
	// used for RMS calculation
	private static double calcRMS(AudioInputStream stream,int maxLength) throws IOException, UnsupportedAudioFileException {
		AudioFormat format=stream.getFormat();
		if(format.getSampleSizeInBits()!=16) {
			throw new UnsupportedAudioFileException("Only 16bit files are supported for volume correction.");
		}
		if(format.getChannels()!=1 && format.getChannels()!=2) {
			throw new UnsupportedAudioFileException("The number of channels is not supported for volume correction.");
		}
		// length in frames
		long length=stream.getFrameLength();
		long limit=(maxLength<=VOL_CORR_MAX_WINDOW?maxLength:VOL_CORR_MAX_WINDOW)*(int)format.getFrameRate();
		if(length>limit){length=limit;}
		//length=1<<(int)(Math.log(length)/Math.log(2));
		//System.out.println("using length: "+length);
		byte[] byteBuffer=new byte[1<<(VOL_CORR_BUFFER_LENGTH+1)];
		if(format.getChannels()==1) {
			int n=(int)(length>>VOL_CORR_BUFFER_LENGTH);
			char[] buffer;
			long meanSum=0;
			int temp;
			int read;
			for(int i=0;i<n;i++) {
				read=stream.read(byteBuffer);
				buffer=Util.bytesToChars(byteBuffer,0,read,format.isBigEndian());
				for(int j=0,m=buffer.length;j<m;j++) {
					temp=buffer[j]-32768;
					meanSum+=temp*temp;
				}
				//meanSum+=calcMSMono(buffer,0,VOL_CORR_BUFFER_LENGTH);
			}
			meanSum/=n;
			return Math.sqrt(meanSum);
		} else {
			int n=(int)(length>>(VOL_CORR_BUFFER_LENGTH-1));
			char[] buffer;
			long meanSumLeft=0;
			long meanSumRight=0;
			int temp;
			int read;
			for(int i=0;i<n;i++) {
				read=stream.read(byteBuffer);
				buffer=Util.bytesToChars(byteBuffer,0,read,format.isBigEndian());
				for(int j=0,m=buffer.length;j<m;j+=2) {
					temp=buffer[j]-32768;
					meanSumLeft+=temp*temp;
				}
				for(int j=1,m=buffer.length;j<m;j+=2) {
					temp=buffer[j]-32768;
					meanSumRight+=temp*temp;
				}
			}
			meanSumLeft/=n;
			meanSumRight/=n;
			return Math.sqrt((meanSumLeft+meanSumRight)>>1);
		}
	}

	private static char maxSampleValue(AudioInputStream stream) throws IOException,UnsupportedAudioFileException {
		AudioFormat format=stream.getFormat();
		if(format.getSampleSizeInBits()!=16) {
			throw new UnsupportedAudioFileException("Only 16bit files are supported for volume correction.");
		}
		if(format.getChannels()!=1 && format.getChannels()!=2) {
			throw new UnsupportedAudioFileException("The number of channels is not supported for volume correction.");
		}
		// length in frames
		long length=stream.getFrameLength();
		byte[] byteBuffer=new byte[1<<(VOL_CORR_BUFFER_LENGTH+1)];
		if(format.getChannels()==1) {
			int n=(int)(length>>VOL_CORR_BUFFER_LENGTH);
			char[] buffer;
			char maxValue=0;
			char temp;
			int read;
			for(int i=0;i<n;i++) {
				read=stream.read(byteBuffer);
				buffer=Util.bytesToChars(byteBuffer,0,read,format.isBigEndian());
				for(int j=0,m=buffer.length;j<m;j++) {
					temp=(char)Math.abs(buffer[j]-32768);
					if(maxValue<temp){maxValue=temp;}
				}
				//meanSum+=calcMSMono(buffer,0,VOL_CORR_BUFFER_LENGTH);
			}
			return maxValue;
		} else {
			int n=(int)(length>>(VOL_CORR_BUFFER_LENGTH-1));
			char[] buffer;
			char maxValue=0;
			char temp;
			int read;
			for(int i=0;i<n;i++) {
				read=stream.read(byteBuffer);
				buffer=Util.bytesToChars(byteBuffer,0,read,format.isBigEndian());
				for(int j=0,m=buffer.length;j<m;j+=2) {
					temp=(char)Math.abs(buffer[j]-32768);
					if(maxValue<temp){maxValue=temp;}
				}
				for(int j=1,m=buffer.length;j<m;j+=2) {
					temp=(char)Math.abs(buffer[j]-32768);
					if(maxValue<temp){maxValue=temp;}
				}
			}
			return maxValue;
		}
	}

	public static float calcVolumeDifference(Sample a,Sample b) throws IOException, UnsupportedAudioFileException {
		AudioInputStream aStream=a.getStream();
		AudioFormat aFormat=a.getFormat();
		AudioInputStream bStream=b.getStream();
		AudioFormat bFormat=b.getFormat();
		int aOffsetFrames=(int)(aFormat.getFrameRate()*SampleOffset.getOffset(a)/1000.0f);
		aStream.skip(aOffsetFrames*aFormat.getFrameSize());
		int bOffsetFrames=((int)(bFormat.getFrameRate()*SampleOffset.getOffset(b)/1000.0f));
		bStream.skip(bOffsetFrames*bFormat.getFrameSize());
		int minLength=Math.min((int)((aStream.getFrameLength()-aOffsetFrames)/aFormat.getFrameRate()),(int)((bStream.getFrameLength()-bOffsetFrames)/bFormat.getFrameRate()));
		double aRMS=calcRMS(aStream,minLength);
		double bRMS=calcRMS(bStream,minLength);
		double scale=aRMS/bRMS;
		//System.out.println("scale="+scale);
		float gain=(float)(20*Math.log(scale)/Math.log(10));
		//System.out.println("gain="+gain);
		return gain;
	}

	private OffsetCalculator(){}

	public static void configureGains(Sample ref,Sample[] samples) throws IOException,UnsupportedAudioFileException {
		Sample[] s=new Sample[samples.length+1];
		s[0]=ref;
		System.arraycopy(samples,0,s,1,samples.length);
		//configureOffsets(s);
		AudioInputStream refStream=ref.getStream();
		AudioFormat format=ref.getFormat();
		int offsetFrames=(int)(format.getFrameRate()*SampleOffset.getOffset(ref)/1000.0f);
		refStream.skip(offsetFrames*format.getFrameSize());
		int minLength=(int)((refStream.getFrameLength()-offsetFrames)/format.getFrameRate());
		AudioInputStream[] sampleStreams=new AudioInputStream[samples.length];
		for(int i=0;i<samples.length;i++) {
			sampleStreams[i]=samples[i].getStream();
			format=samples[i].getFormat();
			offsetFrames=(int)(format.getFrameRate()*SampleOffset.getOffset(samples[i])/1000.0f);
			sampleStreams[i].skip(offsetFrames*format.getFrameSize());
			minLength=Math.min(minLength,(int)((sampleStreams[i].getFrameLength()-offsetFrames)/format.getFrameRate()));
		}
		double[] maxGain=new double[samples.length+1];
		double refRMS=calcRMS(refStream,minLength);
		refStream.close();
		refStream=ref.getStream();
		maxGain[0]=20*Math.log(32000.0d/(int)maxSampleValue(refStream))/Math.log(10);
		refStream.close();
		double[] sampleRMSs=new double[samples.length];
		double minRMS=refRMS;
		for(int i=0;i<samples.length;i++) {
			sampleRMSs[i]=calcRMS(sampleStreams[i],minLength);
			sampleStreams[i].close();
			sampleStreams[i]=samples[i].getStream();
			maxGain[i+1]=20*Math.log(32000.0d/(int)maxSampleValue(sampleStreams[i]))/Math.log(10);
			sampleStreams[i].close();
			minRMS=minRMS<sampleRMSs[i]?minRMS:sampleRMSs[i];
		}
		double[] relGain=new double[samples.length+1];
		relGain[0]=20*Math.log(minRMS/refRMS)/Math.log(10);
		for(int i=0;i<samples.length;i++) {
			relGain[i+1]=20*Math.log(minRMS/sampleRMSs[i])/Math.log(10);
		}
/*
		System.out.println("maxGain: ");
		for(int i=0;i<samples.length+1;i++) {
			System.out.print(maxGain[i]+", ");
		}
		System.out.println();
		System.out.println("relGain: ");
		for(int i=0;i<samples.length+1;i++) {
			System.out.print(relGain[i]+", ");
		}
		System.out.println();
*/
		double minDiff=Double.MAX_VALUE;
		int minDiffIndex=-1;
		for(int i=0;i<samples.length+1;i++) {
			if(maxGain[i]-relGain[i]<minDiff){minDiff=maxGain[i]-relGain[i];minDiffIndex=i;}
		}
/*
		System.out.println("minDiff = "+minDiff+", index = "+minDiffIndex);
		for(int i=0;i<samples.length+1;i++) {
			relGain[i]=minDiff+relGain[i];
		}
		System.out.println("relGain: ");
		for(int i=0;i<samples.length+1;i++) {
			System.out.print(relGain[i]+", ");
		}
		System.out.println();
*/
		for(int i=0;i<samples.length;i++) {
			SampleGain.setGain(samples[i],(float)relGain[i+1]);
		}
		SampleGain.setGain(ref,(float)relGain[0]);
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -