2010-02-10 9 views

Répondre

1

Processing a WAV file header

astuce suivante est un peu plus difficile que le format de données interne pourrait être une variété de types de données. Si vous regardez votre fichier Windows WAV classique, il est probablement juste PCM 16 bits ou peut-être 8 bits. Ce qui signifie que vous pouvez facilement charger les données dans un octet ou un tableau court.

Cependant, vous trouverez d'autres formats. Lorsque vous connaissez le type que vous avez, google. Vous trouverez des informations pour la plupart.

0

Comment ouvrir une vague de fluxEntrée

// 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(); 

Après cela, un fichier WAVE typicall est PCM codé (il y a d'autres codecs, comme flotteurs). Vous devez lire les exemples de markSupportedInputStream. PCM comprend de nombreuses combinaisons de paramètres: (Mono | Stéréo), (Signé | Non signé), (8 bits | 16 bits), (Big Endian | Little Endian pour plus de 8 bits). Vous pouvez comprendre cela sur l'objet format comme format.getChannels(). Pour cette raison, j'ai écrit une classe PcmCodec avec des méthodes comme decodeUnsigned16BitLittleEndian(buffer, offset). Et je normalise les valeurs de l'échantillon à [-1,1].

Voici comment je savoir ce que PCM est:

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; 
} 

Voici un exemple que je décode un PCM spécial: Vous devez lire markSupportedInputStream dans un tableau d'octets (tampon). Après cela, vous pouvez décoder les octets:

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; 
}