【问题标题】:wav amplitude in java (stereo or more channels)java中的wav幅度(立体声或更多通道)
【发布时间】:2010-02-10 12:23:29
【问题描述】:

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

谢谢!

【问题讨论】:

    标签: java audio wav


    【解决方案1】:

    Processing a WAV file header

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

    但是,您会发现其他格式。当你知道你拥有的类型时,谷歌它。您会找到大多数信息。

    【讨论】:

      【解决方案2】:

      如何从 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 包含多种参数组合:(Mono|Stereo)、(Signed|Unsigned)、(8 Bit|16 Bit)、(Big Endian|Little Endian for more than 8 Bit)。您可以在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;
      }
      

      【讨论】:

        猜你喜欢
        • 2015-08-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-07-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多