Package nz.govt.natlib.adapter.wav

Source Code of nz.govt.natlib.adapter.wav.WaveAdapter

/*
*  Copyright 2006 The National Library of New Zealand
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*/

package nz.govt.natlib.adapter.wav;

import java.io.File;
import java.io.IOException;

import nz.govt.natlib.adapter.AdapterUtils;
import nz.govt.natlib.adapter.DataAdapter;
import nz.govt.natlib.fx.CompoundElement;
import nz.govt.natlib.fx.ConstantElement;
import nz.govt.natlib.fx.DataSource;
import nz.govt.natlib.fx.Element;
import nz.govt.natlib.fx.FXUtil;
import nz.govt.natlib.fx.FileDataSource;
import nz.govt.natlib.fx.FixedLengthStringElement;
import nz.govt.natlib.fx.IntegerElement;
import nz.govt.natlib.fx.ParserContext;
import nz.govt.natlib.fx.PositionalElement;
import nz.govt.natlib.fx.StringElement;

/**
* WaveAdapter is responsible for extracting metadata out of Audio Wave files.
*
* @author Nic Evans
* @version 1.0
*/
public class WaveAdapter extends DataAdapter {

  /** All WAV files should start with this hex header */
  public static final String WAV_HEADER = "52 49 46 46 xx xx xx xx 57 41 56 45 66 6D 74 20";

  private Element riffElement = new CompoundElement(new String[] { "Length",
      "SubType" }, new Element[] {
      new IntegerElement(IntegerElement.INT_SIZE, false,
          IntegerElement.DECIMAL_FORMAT),
      new FixedLengthStringElement(4), });

  // the compound element "parser" to read a wave header
  private Element wavElement = new CompoundElement(new String[] { "Length",
      "Format", "Channels", "SamplesPerSec", "AverageBytesPerSec",
      "nBlockAlign", "BitsPerSample" }, new Element[] {
      new IntegerElement(IntegerElement.INT_SIZE, false,
          IntegerElement.DECIMAL_FORMAT),
      new IntegerElement(IntegerElement.SHORT_SIZE, false,
          IntegerElement.DECIMAL_FORMAT),
      new IntegerElement(IntegerElement.SHORT_SIZE, false,
          IntegerElement.DECIMAL_FORMAT),
      new IntegerElement(IntegerElement.INT_SIZE, false,
          IntegerElement.DECIMAL_FORMAT),
      new IntegerElement(IntegerElement.INT_SIZE, false,
          IntegerElement.DECIMAL_FORMAT),
      new IntegerElement(IntegerElement.SHORT_SIZE, false,
          IntegerElement.DECIMAL_FORMAT),
      new IntegerElement(IntegerElement.SHORT_SIZE, false,
          IntegerElement.DECIMAL_FORMAT), });

  // the compound element "parser" to read a wave header
  private String[] bextNames = new String[] { "Length", "Description",
      "Originator", "OriginatorRef", "OriginatorDate",
      "OriginatorDateFormat", "OriginatorTime", "OriginatorTimeFormat",
      "TimeReferenceLow", "TimeReferenceHi", "Version", "UMID",
      "Reserved", "CodingHistory" };

  Element hidden64 = new PositionalElement(64); // UUID

  Element hidden190 = new PositionalElement(190); // Reserved

  private Element bextElement = new CompoundElement(bextNames, new Element[] {
      new IntegerElement(IntegerElement.INT_SIZE, false,
          IntegerElement.DECIMAL_FORMAT),
      new FixedLengthStringElement(256),
      new FixedLengthStringElement(32),
      new FixedLengthStringElement(32),
      new FixedLengthStringElement(10),
      new ConstantElement("'yyyy-mm-dd'"),
      new FixedLengthStringElement(8),
      new ConstantElement("'hh:mm:ss'"),
      new IntegerElement(IntegerElement.INT_SIZE, false,
          IntegerElement.DECIMAL_FORMAT),
      new IntegerElement(IntegerElement.INT_SIZE, false,
          IntegerElement.DECIMAL_FORMAT),
      new IntegerElement(IntegerElement.INT_SIZE, false,
          IntegerElement.DECIMAL_FORMAT), hidden64, // UUID
      hidden190, // Reserved
      new StringElement(), });

  // the compound element "parser" to read a wave data
  private Element genericElement = new CompoundElement(
      new String[] { "Length" }, new Element[] { new IntegerElement(
          IntegerElement.INT_SIZE, false,
          IntegerElement.DECIMAL_FORMAT), });

  public WaveAdapter() {
    hidden64.setInternal(true);
    hidden190.setInternal(true);
  }

  public boolean acceptsFile(File file) {
    return checkFileHeader(file, WAV_HEADER);
  }

  public String getOutputType() {
    return "wav.dtd";
  }

  public String getInputType() {
    return "audio/wav";
  }

  public String getName() {
    return "Microsoft WAV Audio Adapter";
  }

  public String getDescription() {
    return "Adapts all Microsoft WAV audio files, includes BWF";
  }

  public String getVersion() {
    return "2.0";
  }

  public void adapt(File file, ParserContext ctx) throws IOException {
    // add the MetaData to the tree!
    DataSource ftk = null;
   
    try {
      ftk = new FileDataSource(file);
     
      ctx.fireStartParseEvent("WAV");
      writeFileInfo(file, ctx);
 
      ctx.fireStartParseEvent("RIFF");
 
      // move 4 bytes in (for the RIFF tag)
      ftk.setPosition(4);
      riffElement.read(ftk, ctx);
 
      ctx.fireEndParseEvent("RIFF");
 
      // 1. is there a chunk to be read...
      long chunkSize = 12;
      long riffHeaderLength = ctx.getIntAttribute("WAV.RIFF.length");
      while (chunkSize < riffHeaderLength) {
        // 2. read the chunk...
        // get the file position...
        long startPos = ftk.getPosition();
        long reportedLength = 0;
        // read the type;
        String st = FXUtil.getFixedStringValue(ftk, 4);
 
        // 3. process the chunk...
        Element parser = null;
        // get data for the type of block it is...
        if ("fmt ".equals(st)) {
          ctx.fireStartParseEvent("Wave");
          ctx.fireParseEvent("type", st);
          wavElement.read(ftk, ctx);
          ctx.fireEndParseEvent("Wave");
          reportedLength = ctx.getIntAttribute("WAV.Wave.length");
          // break; // only want the first format tag...
        } else if ("data".equals(st)) {
          ctx.fireStartParseEvent("data");
          ctx.fireParseEvent("type", st);
          genericElement.read(ftk, ctx);
          ctx.fireEndParseEvent("data");
          reportedLength = ctx.getIntAttribute("WAV.data.length");
        } else if ("bext".equals(st)) {
          // System.out.println("Broadcast Wave Format extension chunk
          // found");
          ctx.fireStartParseEvent("bext");
          ctx.fireParseEvent("type", st);
          bextElement.read(ftk, ctx);
          ctx.fireEndParseEvent("bext");
          reportedLength = ctx.getIntAttribute("WAV.bext.length");
 
          // debug the bext
          // System.out.println("BEXT ->");
          // for (int i=0;i<bextNames.length;i++) {
          // System.out.println(bextNames[i]+"="+ctx.getAttribute("WAV.bext."+bextNames[i]));
          // }
        } else {
          // System.out.println("Unknown RIFF chunk :"+st);
          ctx.fireStartParseEvent("unknown");
          ctx.fireParseEvent("type", st);
          genericElement.read(ftk, ctx);
          ctx.fireEndParseEvent("unknown");
          reportedLength = ctx.getIntAttribute("WAV.unknown.length");
        }
 
        // work out if there is any padding at the end of the chunk
        long endPos = ftk.getPosition();
        long moveTo = startPos + reportedLength + 8; // the 8's 'cause
        // there's a 2 word
        // format/length
        // added to the
        // chunk at the
        // start
 
        // repositioning
        // System.out.println("Repo :");
        // System.out.println(" Reported Length :"+reportedLength);
        // System.out.println(" End :"+endPos);
        // System.out.println(" Start :"+startPos);
        // System.out.println(" Move Formula :"+moveTo);
 
        // 4. move the file pointer to the next chunk...
        ftk.setPosition(moveTo);
        // 5. loop...
        chunkSize += (reportedLength + 8);
      }
      ctx.fireEndParseEvent("WAV");
    }
    finally {
      AdapterUtils.close(ftk);
    }
  }

  private static String getTime(long ms) {
    // min:sec.ms
    long min = ms / 60000;
    long sec = (ms - (min * 60000)) / 1000;
    long milli = (ms - (min * 60000) - (sec * 1000));
    return min + ":" + sec + "." + milli;
  }

}
TOP

Related Classes of nz.govt.natlib.adapter.wav.WaveAdapter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.