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

📄 samplerateconversionprovider.java

📁 linux下建立JAVA虚拟机的源码KAFFE
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/* *	SampleRateConversionProvider.java *//* *  Copyright (c) 2001 by Florian Bomers <florian@bome.com> * * *   This program is free software; you can redistribute it and/or modify *   it under the terms of the GNU Library General Public License as published *   by the Free Software Foundation; either version 2 of the License, or *   (at your option) any later version. * *   This program is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU Library General Public License for more details. * *   You should have received a copy of the GNU Library General Public *   License along with this program; if not, write to the Free Software *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */package	org.tritonus.sampled.convert;import java.io.IOException;import java.util.Arrays;import java.util.Iterator;import javax.sound.sampled.AudioFormat;import javax.sound.sampled.AudioInputStream;import javax.sound.sampled.AudioSystem;import org.tritonus.share.ArraySet;import org.tritonus.share.TDebug;import org.tritonus.share.sampled.AudioFormats;import org.tritonus.share.sampled.AudioUtils;import org.tritonus.share.sampled.FloatSampleBuffer;import org.tritonus.share.sampled.convert.TSimpleFormatConversionProvider;/** * This provider converts sample rate of 2 PCM streams. <br> * It does: * <ul><li>conversion of different sample rates * <li>conversion of unsigned/signed (only 8bit unsigned supported) * <li>conversion of big/small endian * <li>8,16,24,32 bit conversion * </ul> * It does NOT: * <ul><li>change channel count * <li>accept a stream where the sample rates are equal. This case should be handled * by the PCM2PCM converter * </ul> * * @author Florian Bomers */public class SampleRateConversionProvider	extends TSimpleFormatConversionProvider {	// only used as abbreviation	public static AudioFormat.Encoding PCM_SIGNED=AudioFormat.Encoding.PCM_SIGNED;	public static AudioFormat.Encoding PCM_UNSIGNED=AudioFormat.Encoding.PCM_UNSIGNED;	private static final boolean DEBUG_STREAM=false;	private static final boolean DEBUG_STREAM_PROBLEMS=false;	private static final int ALL=AudioSystem.NOT_SPECIFIED;	private static final AudioFormat[]	OUTPUT_FORMATS = {	    // Encoding, SampleRate, sampleSizeInBits, channels, frameSize, frameRate, bigEndian	    new AudioFormat(PCM_SIGNED, ALL, 8, ALL, ALL, ALL, false),	    new AudioFormat(PCM_SIGNED, ALL, 8, ALL, ALL, ALL, true),	    new AudioFormat(PCM_UNSIGNED, ALL, 8, ALL, ALL, ALL, false),	    new AudioFormat(PCM_UNSIGNED, ALL, 8, ALL, ALL, ALL, true),	    new AudioFormat(PCM_SIGNED, ALL, 16, ALL, ALL, ALL, false),	    new AudioFormat(PCM_SIGNED, ALL, 16, ALL, ALL, ALL, true),	    new AudioFormat(PCM_SIGNED, ALL, 24, ALL, ALL, ALL, false),	    new AudioFormat(PCM_SIGNED, ALL, 24, ALL, ALL, ALL, true),	    new AudioFormat(PCM_SIGNED, ALL, 32, ALL, ALL, ALL, false),	    new AudioFormat(PCM_SIGNED, ALL, 32, ALL, ALL, ALL, true),	};	/**	Constructor.	 */	public SampleRateConversionProvider() {		super(Arrays.asList(OUTPUT_FORMATS),		      Arrays.asList(OUTPUT_FORMATS));	}	public AudioInputStream getAudioInputStream(AudioFormat targetFormat, AudioInputStream sourceStream) {		AudioFormat sourceFormat=sourceStream.getFormat();		// the non-conversion case		if (AudioFormats.matches(sourceFormat, targetFormat)) {			return sourceStream;		}		targetFormat=replaceNotSpecified(sourceFormat, targetFormat);		// do not support NOT_SPECIFIED as sample rates		if (targetFormat.getSampleRate()!=AudioSystem.NOT_SPECIFIED			&& sourceFormat.getSampleRate()!=AudioSystem.NOT_SPECIFIED			&& targetFormat.getChannels()!=AudioSystem.NOT_SPECIFIED			&& sourceFormat.getChannels()!=AudioSystem.NOT_SPECIFIED			&& targetFormat.getSampleSizeInBits()!=AudioSystem.NOT_SPECIFIED			&& sourceFormat.getSampleSizeInBits()!=AudioSystem.NOT_SPECIFIED			&& isConversionSupported(sourceFormat, targetFormat)) {			return new SampleRateConverterStream(sourceStream, targetFormat);		}		throw new IllegalArgumentException("format conversion not supported");	}		// replaces the sample rate and frame rate. 	// Should only be used with PCM_SIGNED or PCM_UNSIGNED	private static AudioFormat replaceSampleRate(AudioFormat format, float newSampleRate) {		if (format.getSampleRate()==newSampleRate) {			return format;		}		return new AudioFormat(format.getEncoding(), newSampleRate, format.getSampleSizeInBits(), 			format.getChannels(), format.getFrameSize(), newSampleRate, format.isBigEndian());	}	private static final float[] commonSampleRates={		8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, 88200, 96000	};	public AudioFormat[] getTargetFormats(AudioFormat.Encoding targetEncoding,	                                      AudioFormat sourceFormat) {		if (TDebug.TraceAudioConverter) {			TDebug.out(">SampleRateConversionProvider.getTargetFormats(AudioFormat.Encoding, AudioFormat):");			TDebug.out("checking out possible target formats");			TDebug.out("from: " + sourceFormat);			TDebug.out("to  : " + targetEncoding);		}		float sourceSampleRate=sourceFormat.getSampleRate();		// a trick: set sourceFormat's sample rate to -1 so that		//          replaceNotSpecified does not replace the sample rate.		//          we want to convert that !		sourceFormat=replaceSampleRate(sourceFormat, AudioSystem.NOT_SPECIFIED);		if (isConversionSupported(targetEncoding, sourceFormat)) {			ArraySet result=new ArraySet();			Iterator iterator=getCollectionTargetFormats().iterator();			while (iterator.hasNext()) {				AudioFormat targetFormat = (AudioFormat) iterator.next();				targetFormat=replaceNotSpecified(sourceFormat, targetFormat);				if (isConversionSupported(targetFormat, sourceFormat)) {					result.add(targetFormat);				}			}			// for convenience, add some often used sample rates as output			// this may help applications that do not handle NOT_SPECIFIED			if (result.size()>0 				&& sourceSampleRate!=AudioSystem.NOT_SPECIFIED) {				int count=result.size();				for (int i=0; i<count; i++) {					AudioFormat format=(AudioFormat) result.get(i);					for (int j=0; j<commonSampleRates.length; j++) {						if (!doMatch(sourceSampleRate, commonSampleRates[j])) {							result.add(replaceSampleRate(format, commonSampleRates[j]));						}					}				}			}			if (TDebug.TraceAudioConverter) {				TDebug.out("<found "+result.size()+" matching formats.");			}			return (AudioFormat[]) result.toArray(EMPTY_FORMAT_ARRAY);		} else {			if (TDebug.TraceAudioConverter) {				TDebug.out("<returning empty array.");			}			return EMPTY_FORMAT_ARRAY;		}	}	// overriden	public boolean isConversionSupported(AudioFormat targetFormat,	                                     AudioFormat sourceFormat) {		// do not match when targetSampleRate set and sourceSamplerate set and NOT both the same		boolean result=(targetFormat.getSampleRate()==AudioSystem.NOT_SPECIFIED				|| targetFormat.getSampleRate()==AudioSystem.NOT_SPECIFIED				|| !doMatch(targetFormat.getSampleRate(), sourceFormat.getSampleRate())			&& doMatch(targetFormat.getChannels(), sourceFormat.getChannels()))			&& AudioUtils.containsFormat(sourceFormat, getCollectionSourceFormats().iterator())			&& AudioUtils.containsFormat(targetFormat, getCollectionTargetFormats().iterator());		if (TDebug.TraceAudioConverter) {			TDebug.out(">SampleRateConverter: isConversionSupported(AudioFormat, AudioFormat):");			TDebug.out("checking if conversion possible");			TDebug.out("from: " + sourceFormat);			TDebug.out("to  : " + targetFormat);			TDebug.out("< result : " + result);		}		return result;	}		private static long convertLength(AudioFormat sourceFormat, AudioFormat targetFormat, long sourceLength) {		if (sourceLength==AudioSystem.NOT_SPECIFIED) {			return sourceLength;		}		return Math.round(targetFormat.getSampleRate()/sourceFormat.getSampleRate()*sourceLength);		//return (long) (targetFormat.getSampleRate()/sourceFormat.getSampleRate()*sourceLength);	}	/**	 * SampleRateConverterStream	 */	// at the moment, there are so many special things to care	// about, and new things in an AIS, that I derive directly from	// AudioInputStream.	// I cannot use TAsynchronousFilteredAudioInputStream because	// - it doesn't allow convenient use of a history. The history will be needed	//   especially when performing filtering	// - it doesn't work on FloatSampleBuffer (yet)	// - each sample must be calculated one-by-one. The asynchronous	//   difficulty isn't overcome by using a TCircularBuffer	// I cannot use TSynchronousFilteredAudioInputStream because	// - it doesn't handle different sample rates	// Later we can make a base class for this, e.g. THistoryAudioInputStream		// TODO: when target sample rate is < source sample rate (or only slightly above),	// this stream calculates ONE sample too much.	public static class SampleRateConverterStream extends AudioInputStream {		/** the current working buffer with samples of the sourceStream */		private FloatSampleBuffer thisBuffer=null;		/** used when read(byte[],int,int) is called */		private FloatSampleBuffer writeBuffer=null;		private byte[] byteBuffer; // used for reading samples of sourceStream		private AudioInputStream sourceStream;		private float sourceSampleRate;		private float targetSampleRate;		/** index in thisBuffer */		private double dPos;		/** Conversion algorithm */		public static final int SAMPLE_AND_HOLD=1;		/** Conversion algorithm */		public static final int LINEAR_INTERPOLATION=2;		/** Conversion algorithm */		public static final int RESAMPLE=3;				/** source stream is read in buffers of this size - in milliseconds */		private int sourceBufferTime;		/** the current conversion algorithm */		private int conversionAlgorithm=LINEAR_INTERPOLATION;		//private int conversionAlgorithm=SAMPLE_AND_HOLD;				// History support		/** the buffer with history samples */		private FloatSampleBuffer historyBuffer=null;		/** the minimum number of samples that must be present in the history buffer */		private int minimumSamplesInHistory=1;				/** force to discard current contents in thisBuffer if true */		private boolean thisBufferValid=false;		public SampleRateConverterStream(AudioInputStream sourceStream, AudioFormat targetFormat) {			// clean up targetFormat:			// - ignore frame rate totally			// - recalculate frame size			super (sourceStream, new SRCAudioFormat(targetFormat), 			           convertLength(sourceStream.getFormat(), targetFormat, sourceStream.getFrameLength()));			if (TDebug.TraceAudioConverter) {				TDebug.out("SampleRateConverterStream: <init>");			}			this.sourceStream=sourceStream;			sourceSampleRate=sourceStream.getFormat().getSampleRate();			targetSampleRate=targetFormat.getSampleRate();			dPos=0;			// use a buffer size of 100ms			sourceBufferTime=100;			resizeBuffers();			flush(); // force read of source stream next time read is called		}				/**		 * Assures that both historyBuffer and working buffer		 * <ul><li>exist		 * <li>have about <code>sourceBufferTime</code> ms samples		 * <li>that both have at least <code>minimumSamplesInHistory</code>		 * samples		 * </ul>		 * This method must be called when anything is changed that		 * may change the size of the buffers.		 */		private synchronized void resizeBuffers() {			int bufferSize=(int) AudioUtils.millis2Frames(				(long) sourceBufferTime, sourceSampleRate);			if (bufferSize<minimumSamplesInHistory) {				bufferSize=minimumSamplesInHistory;			}			// we must be able to calculate at least one output sample from			// one input buffer block			if (bufferSize<outSamples2inSamples(1)) {				bufferSize=roundUp(outSamples2inSamples(1));			}			if (historyBuffer==null) {				historyBuffer=new FloatSampleBuffer(sourceStream.getFormat().getChannels(),					bufferSize, sourceSampleRate);				historyBuffer.makeSilence();			}			// TODO: retain last samples !			historyBuffer.changeSampleCount(bufferSize, true);			if (thisBuffer==null) {				thisBuffer=new FloatSampleBuffer(sourceStream.getFormat().getChannels(),					bufferSize, sourceSampleRate);			}			// TODO: retain last samples and adjust dPos			thisBuffer.changeSampleCount(bufferSize, true);		}				/**		 * Reads from a source stream that cannot handle float buffers.		 * After this method has been called, it is to be checked whether		 * we are closed !		 */		private synchronized void readFromByteSourceStream() throws IOException {			int byteCount=thisBuffer.getByteArrayBufferSize(getFormat());			if (byteBuffer==null || byteBuffer.length<byteCount) {				byteBuffer=new byte[byteCount];			}			// finally read it			int bytesRead=0;			int thisRead;			do {				thisRead=sourceStream.read(byteBuffer, bytesRead, byteCount-bytesRead);				if (thisRead>0) {					bytesRead+=thisRead;				}			} while (bytesRead<byteCount && thisRead>0);			if (bytesRead==0) {				// sourceStream is closed. We don't accept 0 bytes read from source stream				close();			} else {				thisBuffer.initFromByteArray(byteBuffer, 0, bytesRead, sourceStream.getFormat());			}		}				private synchronized void readFromFloatSourceStream() throws IOException {			//((FloatSampleInput) sourceStream).read(thisBuffer);		}		private long testInFramesRead=0;private long testOutFramesReturned=0;		/**		 * fills thisBuffer with new samples.		 * It sets the history buffer to the last buffer.		 * thisBuffer's sampleCount will be the number of samples read.		 * Calling methods MUST check whether this stream is closed upon		 * completion of this method. If the stream is closed, the contents		 * of <code>thisBuffer</code> are not valid.		 */		private synchronized void readFromSourceStream() throws IOException {			if (isClosed()) {				return;			}			int oldSampleCount=thisBuffer.getSampleCount();			// reuse history buffer			FloatSampleBuffer newBuffer=historyBuffer;			historyBuffer=thisBuffer;			thisBuffer=newBuffer;			if (sourceStream.getFrameLength()!=AudioSystem.NOT_SPECIFIED 				&& thisBuffer.getSampleCount()+testInFramesRead>sourceStream.getFrameLength()) {					if (sourceStream.getFrameLength()-testInFramesRead<=0) {						close();						return;					}					thisBuffer.changeSampleCount((int) (sourceStream.getFrameLength()-testInFramesRead), false);			}								// if (sourceStream instanceof FloatSampleInput) {			//	readFromFloatSourceStream();			// } else {				readFromByteSourceStream();			// }			if (TDebug.TraceAudioConverter) {				testInFramesRead+=thisBuffer.getSampleCount();				if (DEBUG_STREAM) {					TDebug.out("Read "+thisBuffer.getSampleCount()+" frames from source stream. Total="+testInFramesRead);				}			}			double inc=outSamples2inSamples(1.0);			if (!thisBufferValid) {				thisBufferValid=true;				//dPos=inc/2;				dPos=0.0;			} else {				double temp=dPos;				dPos-=(double) oldSampleCount;				if (DEBUG_STREAM) {					TDebug.out("new dPos: "+temp+" - "+oldSampleCount+" = "+dPos);				}				if ((dPos>inc || dPos<-inc) && roundDown(dPos)!=0) {					// hard-reset dPos if - why ever - it got out of bounds					if (DEBUG_STREAM_PROBLEMS) {						TDebug.out("Need to hard reset dPos="+dPos+" !!!!!!!!!!!!!!!!!!!!!!!");					}					//dPos=inc/2;					dPos=0.0;				}			}

⌨️ 快捷键说明

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