📄 floatsamplebuffer.java
字号:
*/ public int getByteArrayBufferSize(AudioFormat format) { if (!format.getEncoding().equals(AudioFormat.Encoding.PCM_SIGNED) && !format.getEncoding().equals(AudioFormat.Encoding.PCM_UNSIGNED)) { throw new IllegalArgumentException ("FloatSampleBuffer: only PCM samples are possible."); } int bytesPerSample=format.getSampleSizeInBits()/8; int bytesPerFrame=bytesPerSample*format.getChannels(); return bytesPerFrame*getSampleCount(); } /** * @return number of bytes copied to buffer * @throws Exception when buffer is too small or <code>format</code> doesn't match */ public int convertToByteArray(byte[] buffer, int offset, AudioFormat format) { int byteCount=getByteArrayBufferSize(format); if (offset+byteCount>buffer.length) { throw new IllegalArgumentException ("FloatSampleBuffer.convertToByteArray: buffer too small."); } boolean signed=format.getEncoding().equals(AudioFormat.Encoding.PCM_SIGNED); if (!signed && !format.getEncoding().equals(AudioFormat.Encoding.PCM_UNSIGNED)) { throw new IllegalArgumentException ("FloatSampleBuffer.convertToByteArray: only PCM samples are allowed."); } if (format.getSampleRate()!=getSampleRate()) { throw new IllegalArgumentException ("FloatSampleBuffer.convertToByteArray: different samplerates."); } if (format.getChannels()!=getChannelCount()) { throw new IllegalArgumentException ("FloatSampleBuffer.convertToByteArray: different channel count."); } int bytesPerSample=format.getSampleSizeInBits()/8; int bytesPerFrame=bytesPerSample*format.getChannels(); int formatType=getFormatType(format.getSampleSizeInBits(), signed, format.isBigEndian()); for (int ch=0; ch<format.getChannels(); ch++) { convertFloatToByte(getChannel(ch), sampleCount, buffer, offset, bytesPerFrame, formatType); offset+=bytesPerSample; // next channel } return getSampleCount()*bytesPerFrame; } /** * Creates a new byte[] buffer and returns it. * Throws an exception when sample rate doesn't match. * @see #convertToByteArray(byte[], int, AudioFormat) */ public byte[] convertToByteArray(AudioFormat format) { // throws exception when sampleRate doesn't match // creates a new byte[] buffer and returns it byte[] res=new byte[getByteArrayBufferSize(format)]; convertToByteArray(res, 0, format); return res; } //////////////////////////////// actions ///////////////////////////////// /** * Resizes this buffer. * <p>If <code>keepOldSamples</code> is true, as much as possible samples are * retained. If the buffer is enlarged, silence is added at the end. * If <code>keepOldSamples</code> is false, existing samples are discarded * and the buffer contains random samples. */ public void changeSampleCount(int newSampleCount, boolean keepOldSamples) { int oldSampleCount=getSampleCount(); if (oldSampleCount==newSampleCount) { return; } Object[] oldChannels=null; if (keepOldSamples) { oldChannels=getAllChannels(); } init(getChannelCount(), newSampleCount, getSampleRate()); if (keepOldSamples) { // copy old channels and eventually silence out new samples int copyCount=newSampleCount<oldSampleCount? newSampleCount:oldSampleCount; for (int ch=0; ch<getChannelCount(); ch++) { float[] oldSamples=(float[]) oldChannels[ch]; float[] newSamples=(float[]) getChannel(ch); if (oldSamples!=newSamples) { // if this sample array was not object of lazy delete System.arraycopy(oldSamples, 0, newSamples, 0, copyCount); } if (oldSampleCount<newSampleCount) { // silence out new samples for (int i=oldSampleCount; i<newSampleCount; i++) { newSamples[i]=0.0f; } } } } } public void makeSilence() { // silence all channels if (getChannelCount()>0) { makeSilence(0); for (int ch=1; ch<getChannelCount(); ch++) { copyChannel(0, ch); } } } public void makeSilence(int channel) { float[] samples=getChannel(0); for (int i=0; i<getSampleCount(); i++) { samples[i]=0.0f; } } public void addChannel(boolean silent) { // creates new, silent channel insertChannel(getChannelCount(), silent); } /** * lazy insert of a (silent) channel at position <code>index</code>. */ public void insertChannel(int index, boolean silent) { insertChannel(index, silent, LAZY_DEFAULT); } /** * Inserts a channel at position <code>index</code>. * <p>If <code>silent</code> is true, the new channel will be silent. * Otherwise it will contain random data. * <p>If <code>lazy</code> is true, hidden channels which have at least getSampleCount() * elements will be examined for reusage as inserted channel.<br> * If <code>lazy</code> is false, still hidden channels are reused, * but it is assured that the inserted channel has exactly getSampleCount() elements, * thus not wasting memory. */ public void insertChannel(int index, boolean silent, boolean lazy) { int physSize=channels.size(); int virtSize=getChannelCount(); float[] newChannel=null; if (physSize>virtSize) { // there are hidden channels. Try to use one. for (int ch=virtSize; ch<physSize; ch++) { float[] thisChannel=(float[]) channels.get(ch); if ((lazy && thisChannel.length>=getSampleCount()) || (!lazy && thisChannel.length==getSampleCount())) { // we found a matching channel. Use it ! newChannel=thisChannel; channels.remove(ch); break; } } } if (newChannel==null) { newChannel=new float[getSampleCount()]; } channels.add(index, newChannel); this.channelCount++; if (silent) { makeSilence(index); } } /** performs a lazy remove of the channel */ public void removeChannel(int channel) { removeChannel(channel, LAZY_DEFAULT); } /** * Removes a channel. * If lazy is true, the channel is not physically removed, but only hidden. * These hidden channels are reused by subsequent calls to addChannel * or insertChannel. */ public void removeChannel(int channel, boolean lazy) { if (!lazy) { channels.remove(channel); } else if (channel<getChannelCount()-1) { // if not already, move this channel at the end channels.add(channels.remove(channel)); } channelCount--; } /** * both source and target channel have to exist. targetChannel * will be overwritten */ public void copyChannel(int sourceChannel, int targetChannel) { float[] source=getChannel(sourceChannel); float[] target=getChannel(targetChannel); System.arraycopy(source, 0, target, 0, getSampleCount()); } /** * Copies data inside all channel. When the 2 regions * overlap, the behavior is not specified. */ public void copy(int sourceIndex, int destIndex, int length) { for (int i=0; i<getChannelCount(); i++) { copy(i, sourceIndex, destIndex, length); } } /** * Copies data inside a channel. When the 2 regions * overlap, the behavior is not specified. */ public void copy(int channel, int sourceIndex, int destIndex, int length) { float[] data=getChannel(channel); int bufferCount=getSampleCount(); if (sourceIndex+length>bufferCount || destIndex+length>bufferCount || sourceIndex<0 || destIndex<0 || length<0) { throw new IndexOutOfBoundsException("parameters exceed buffer size"); } System.arraycopy(data, sourceIndex, data, destIndex, length); } /** * Mix up of 1 channel to n channels.<br> * It copies the first channel to all newly created channels. * @param targetChannelCount the number of channels that this sample buffer * will have after expanding. NOT the number of * channels to add ! * @exception IllegalArgumentException if this buffer does not have one * channel before calling this method. */ public void expandChannel(int targetChannelCount) { // even more sanity... if (getChannelCount()!=1) { throw new IllegalArgumentException( "FloatSampleBuffer: can only expand channels for mono signals."); } for (int ch=1; ch<targetChannelCount; ch++) { addChannel(false); copyChannel(0, ch); } } /** * Mix down of n channels to one channel.<br> * It uses a simple mixdown: all other channels are added to first channel.<br> * The volume is NOT lowered ! * Be aware, this might cause clipping when converting back * to integer samples. */ public void mixDownChannels() { float[] firstChannel=getChannel(0); int sampleCount=getSampleCount(); int channelCount=getChannelCount(); for (int ch=channelCount-1; ch>0; ch--) { float[] thisChannel=getChannel(ch); for (int i=0; i<sampleCount; i++) { firstChannel[i]+=thisChannel[i]; } removeChannel(ch); } } public void setSamplesFromBytes(byte[] srcBuffer, int srcOffset, AudioFormat format, int destOffset, int lengthInSamples) { int bytesPerSample = (format.getSampleSizeInBits() + 7)/8; int bytesPerFrame = bytesPerSample * format.getChannels(); if (srcOffset + (lengthInSamples * bytesPerFrame) > srcBuffer.length) { throw new IllegalArgumentException ("FloatSampleBuffer.setSamplesFromBytes: srcBuffer too small."); } if (destOffset + lengthInSamples > getSampleCount()) { throw new IllegalArgumentException ("FloatSampleBuffer.setSamplesFromBytes: destBuffer too small."); } boolean signed = format.getEncoding().equals(AudioFormat.Encoding.PCM_SIGNED); boolean unsigned = format.getEncoding().equals(AudioFormat.Encoding.PCM_UNSIGNED); if (!signed && !unsigned) { throw new IllegalArgumentException ("FloatSampleBuffer: only PCM samples are possible."); } int formatType = getFormatType(format.getSampleSizeInBits(), signed, format.isBigEndian()); for (int ch = 0; ch < format.getChannels(); ch++) { convertByteToFloat(srcBuffer, srcOffset, bytesPerFrame, formatType, getChannel(ch), destOffset, lengthInSamples); srcOffset += bytesPerSample; // next channel } } //////////////////////////////// properties ///////////////////////////////// public int getChannelCount() { return channelCount; } public int getSampleCount() { return sampleCount; } public float getSampleRate() { return sampleRate; } /** * Sets the sample rate of this buffer. * NOTE: no conversion is done. The samples are only re-interpreted. */ public void setSampleRate(float sampleRate) { if (sampleRate<=0) { throw new IllegalArgumentException ("Invalid samplerate for FloatSampleBuffer."); } this.sampleRate=sampleRate; } /** * NOTE: the returned array may be larger than sampleCount. So in any case, * sampleCount is to be respected. */ public float[] getChannel(int channel) { if (channel<0 || channel>=getChannelCount()) { throw new IllegalArgumentException(
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -