java中的wav幅度(立体声或更多声道)

您有没有人知道如何在Java中找到WAV文件中的幅度? 如果文件是立体声(或有更多通道),如何将数据放入数组?

谢谢!

处理WAV文件头

下一个技巧更具挑战性,因为内部数据格式可能是各种数据类型。 如果您正在查看经典的Windows WAV文件,它可能只是PCM 16位或8位。 这意味着,您可以轻松地将数据加载到字节或短数组中。

但是,您会找到其他格式。 当您知道自己的类型时,请将其谷歌。 你会找到最多的信息。

如何从inputStream打开WAVE

// The WAVE-File-Reader of Java needs to reset on marks final InputStream markSupportedInputStream; if (inputStream.markSupported()) { markSupportedInputStream = inputStream; } else { // BufferedInputStream wraps an InputStream, buffers the read data // and so it can reset on marks // Including RIFF header, format chunk and data chunk, standard // WAVE files have an overall header size of 44 bytes. 8192 Bytes should // be enough. Unconsidered are untypically chucks, like cue chunk, // playlist chunk etc. final int bufferSize = 8192; markSupportedInputStream = new BufferedInputStream(inputStream, bufferSize); } final AudioInputStream stream; try { stream = AudioSystem.getAudioInputStream(markSupportedInputStream); } catch (final UnsupportedAudioFileException e) { throw new UnsuportedFormatException(); } final AudioFormat format = stream.getFormat(); final int numChannels = format.getChannels(); 

之后,典型的WAVE文件是PCM编码的(还有其他编解码器,如浮点数)。 您必须从markSupportedInputStream读取样本。

PCM包括许多参数组合:(单声道|立体声),(有符号|无符号),(8位| 16位),(Big Endian | Little Endian超过8位)。 你可以在format对象上找出这个,比如format.getChannels() 。 出于这个原因,我编写了一个PcmCodec类,其方法类似于decodeUnsigned16BitLittleEndian(buffer, offset) 。 我将样本值规范化为[-1,1]。

这是我如何弄清楚它是什么PCM:

 public static boolean isAudioFormatSupported( final @NonNull AudioFormat format) { final Encoding encoding = format.getEncoding(); final int numChannels = format.getChannels(); final int sampleSizeBits = format.getSampleSizeInBits(); final boolean encodingSupported = (encoding == Encoding.PCM_SIGNED || encoding == Encoding.PCM_UNSIGNED); final boolean channelsSupported = (numChannels == AudioSystem.NOT_SPECIFIED || numChannels == 1 || numChannels == 2); final boolean sampleSizeSupported = (sampleSizeBits == AudioSystem.NOT_SPECIFIED || sampleSizeBits == 8 || sampleSizeBits == 16); return encodingSupported && channelsSupported && sampleSizeSupported; } @NonNull private static Format toInternalFormat(final @NonNull AudioFormat audioFormat) { final Format internalFormat; if (audioFormat.getEncoding().equals(AudioFormat.Encoding.PCM_SIGNED)) { switch (audioFormat.getSampleSizeInBits()) { case 8: internalFormat = Format.SIGNED_8_BIT; break; case 16: case AudioSystem.NOT_SPECIFIED: if (audioFormat.isBigEndian()) { internalFormat = Format.SIGNED_16_BIT_BIG_ENDIAN; } else { internalFormat = Format.SIGNED_16_BIT_LITTLE_ENDIAN; } break; default: throw new AssertionError(audioFormat.getSampleSizeInBits() + " Bit not supported"); } } else if (audioFormat.getEncoding().equals( AudioFormat.Encoding.PCM_UNSIGNED)) { switch (audioFormat.getSampleSizeInBits()) { case 8: internalFormat = Format.UNSIGNED_8_BIT; break; case 16: case AudioSystem.NOT_SPECIFIED: if (audioFormat.isBigEndian()) { internalFormat = Format.UNSIGNED_16_BIT_BIG_ENDIAN; } else { internalFormat = Format.UNSIGNED_16_BIT_LITTLE_ENDIAN; } break; default: throw new AssertionError(audioFormat.getSampleSizeInBits() + " Bit not supported"); } } else { throw new AssertionError("Neither PCM_SIGNED nor PCM_UNSIGNED"); } return internalFormat; } 

下面是我如何解码特殊PCM的示例:您需要从markSupportedInputStream读取到字节数组(缓冲区)。 之后,您可以解码字节:

 public float decodeMono(final @NonNull byte[] buffer, final int offset) { final float sample; switch (format) { case SIGNED_8_BIT: sample = decodeSigned8Bit(buffer, offset); break; case UNSIGNED_8_BIT: sample = decodeUnsigned8Bit(buffer, offset); break; case SIGNED_16_BIT_BIG_ENDIAN: sample = decodeSigned16BitBigEndian(buffer, offset); break; case SIGNED_16_BIT_LITTLE_ENDIAN: sample = decodeSigned16BitLittleEndian(buffer, offset); break; case UNSIGNED_16_BIT_BIG_ENDIAN: sample = decodeUnsigned16BitBigEndian(buffer, offset); break; case UNSIGNED_16_BIT_LITTLE_ENDIAN: sample = decodeUnsigned16BitLittleEndian(buffer, offset); break; default: throw new AssertionError(); } return Util.clamp(sample, -1f, 1f); } private static float decodeUnsigned16BitBigEndian( final @NonNull byte[] buffer, final int offset) { final byte lower, higher; higher = buffer[offset]; lower = buffer[offset + 1]; final int sampleInt = ((higher & 0xff) << 8 | lower & 0xff) - 0x8000; final float sample = (float) sampleInt / (float) 0x7fff; return sample; }