com.drew.metadata.wav.WavRiffHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of metadata-extractor Show documentation
Show all versions of metadata-extractor Show documentation
Java library for extracting EXIF, IPTC, XMP, ICC and other metadata from image and video files.
package com.drew.metadata.wav;
import com.drew.imaging.riff.RiffHandler;
import com.drew.lang.ByteArrayReader;
import com.drew.lang.annotations.NotNull;
import com.drew.metadata.Metadata;
import com.drew.metadata.MetadataException;
import java.io.IOException;
/**
* Implementation of {@link RiffHandler} specialising in Wav support.
*
* Extracts data from chunk/list types:
*
*
* "INFO"
: artist, title, product, track number, date created, genre, comments, copyright, software, duration
* "fmt "
: format, channels, samples/second, bytes/second, block alignment, bits/sample
* "data"
: duration
*
*
* Sources: http://www.neurophys.wisc.edu/auditory/riff-format.txt
* http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html
* http://wiki.audacityteam.org/wiki/WAV
*
* @author Payton Garland
*/
public class WavRiffHandler implements RiffHandler
{
@NotNull
private final WavDirectory _directory;
@NotNull
private String _currentList = "";
public WavRiffHandler(@NotNull Metadata metadata)
{
_directory = new WavDirectory();
metadata.addDirectory(_directory);
}
public boolean shouldAcceptRiffIdentifier(@NotNull String identifier)
{
return identifier.equals(WavDirectory.FORMAT);
}
public boolean shouldAcceptChunk(@NotNull String fourCC)
{
return fourCC.equals(WavDirectory.CHUNK_FORMAT)
|| (_currentList.equals(WavDirectory.LIST_INFO) && WavDirectory._tagIntegerMap.containsKey(fourCC))
|| fourCC.equals(WavDirectory.CHUNK_DATA);
}
@Override
public boolean shouldAcceptList(@NotNull String fourCC)
{
if (fourCC.equals(WavDirectory.LIST_INFO)) {
_currentList = WavDirectory.LIST_INFO;
return true;
} else {
_currentList = "";
return false;
}
}
public void processChunk(@NotNull String fourCC, @NotNull byte[] payload)
{
try {
if (fourCC.equals(WavDirectory.CHUNK_FORMAT)) {
ByteArrayReader reader = new ByteArrayReader(payload);
reader.setMotorolaByteOrder(false);
int wFormatTag = reader.getInt16(0);
int wChannels = reader.getInt16(2);
int dwSamplesPerSec = reader.getInt32(4);
int dwAvgBytesPerSec = reader.getInt32(8);
int wBlockAlign = reader.getInt16(12);
switch (wFormatTag) {
// Microsoft Pulse Code Modulation (PCM)
case (0x0001):
int wBitsPerSample = reader.getInt16(14);
_directory.setInt(WavDirectory.TAG_BITS_PER_SAMPLE, wBitsPerSample);
_directory.setString(WavDirectory.TAG_FORMAT, WavDirectory._audioEncodingMap.get(wFormatTag));
break;
default:
if (WavDirectory._audioEncodingMap.containsKey(wFormatTag)) {
_directory.setString(WavDirectory.TAG_FORMAT, WavDirectory._audioEncodingMap.get(wFormatTag));
} else {
_directory.setString(WavDirectory.TAG_FORMAT, "Unknown");
}
}
_directory.setInt(WavDirectory.TAG_CHANNELS, wChannels);
_directory.setInt(WavDirectory.TAG_SAMPLES_PER_SEC, dwSamplesPerSec);
_directory.setInt(WavDirectory.TAG_BYTES_PER_SEC, dwAvgBytesPerSec);
_directory.setInt(WavDirectory.TAG_BLOCK_ALIGNMENT, wBlockAlign);
} else if (fourCC.equals(WavDirectory.CHUNK_DATA)) {
try {
if (_directory.containsTag(WavDirectory.TAG_BYTES_PER_SEC)) {
double duration = (double)payload.length / _directory.getDouble(WavDirectory.TAG_BYTES_PER_SEC);
Integer hours = (int)duration / (int)(Math.pow(60, 2));
Integer minutes = ((int)duration / (int)(Math.pow(60, 1))) - (hours * 60);
Integer seconds = (int)Math.round((duration / (Math.pow(60, 0))) - (minutes * 60));
String time = String.format("%1$02d:%2$02d:%3$02d", hours, minutes, seconds);
_directory.setString(WavDirectory.TAG_DURATION, time);
}
} catch (MetadataException ex) {
_directory.addError("Error calculating duration: bytes per second not found");
}
}else if (WavDirectory._tagIntegerMap.containsKey(fourCC)) {
_directory.setString(WavDirectory._tagIntegerMap.get(fourCC), new String(payload).substring(0, payload.length - 1));
}
} catch (IOException ex) {
_directory.addError(ex.getMessage());
}
}
@Override
public void addError(@NotNull String message)
{
_directory.addError(message);
}
}