/* * @(#)AudioFormatWAV.java - parse Audioheaders, wav / riff * * Copyright (c) 2003-2008 by dvb.matt, All Rights Reserved. * * This file is part of ProjectX, a free Java based demux utility. * By the authors, ProjectX is intended for educational purposes only, * as a non-commercial test project. * * The part of audio parsing was derived from the MPEG/Audio * Software Simulation Group's audio codec and ATSC A/52 in a special modified manner. * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ package net.sourceforge.dvb.projectx.audio; import java.util.Arrays; import net.sourceforge.dvb.projectx.audio.AudioFormat; public class AudioFormatWAV extends AudioFormat { public AudioFormatWAV() { super(); } private final int WaveChunks[] = { 0x57415645, //0 'WAVE' 0x63756520, //1 'cue ' 0x64617461, //2 'data' 0x66616374, //3 'fact' 0x666D7420, //4 'fmt ' 0x696E7374, //5 'inst' 0x6C61626C, //6 'labl' 0x6C697374, //7 'list' 0x6C747874, //8 'ltxt' 0x6E6F7465, //9 'note' 0x706C7374, //10 'plst' 0x736D706C //11 'smpl' }; /** * parse RIFF_WAVE Header */ public int parseHeader(byte[] frame, int pos) { setINTEL(false); if (frame[pos] != 0x52 || frame[pos + 1] != 0x49 || frame[pos + 2] != 0x46 ) return -1; if (frame[pos + 3] == 0x46) setINTEL(true); else if (frame[pos + 3] != 0x58) return -2; setID(isINTEL() ? 0 : 1); setEmphasis(0); setProtectionBit(0 ^ 1); Arrays.sort(WaveChunks); if (littleEndian(frame, pos + 8, 4, false) != WaveChunks[0]) return -3; int chunk = 0; int chunksize = 0; for (int a = pos + 12; a < frame.length - 4; a++) { if (Arrays.binarySearch(WaveChunks, (chunk = littleEndian(frame, a, 4, false))) < 0) continue; if (chunk == WaveChunks[4]) { //fmt chunk read info datas chunksize = littleEndian(frame, a + 4, 4, isINTEL()); setLayer(littleEndian(frame, a + 8, 2, isINTEL())); // Compression type (1=PCM) setChannel(littleEndian(frame, a + 10, 2, isINTEL())); // channels setSamplingFrequency(littleEndian(frame, a + 12, 4, isINTEL())); // samplerate setBitrate(littleEndian(frame, a + 16, 4, isINTEL()) * 8); // avg bits per second setMode(littleEndian(frame, a + 20, 2, isINTEL())); // block align, bytes per sample setSize(littleEndian(frame, a + 22, 2, isINTEL())); //bits per sample //extrabits not of interest } else if (chunk == WaveChunks[2]) { //data chunk, sample data chunksize = littleEndian(frame, a + 4, 4, isINTEL()); setSizeBase(chunksize); // length of whole sample data setEmphasis(a + 8); // real start of whole sample data } else chunksize = littleEndian(frame, a + 4, 4, isINTEL()); a += chunksize + 3; } //PTS low+high may exists in 'fact' of MPEG1audio ! if (getBitrate() < 1 || getSamplingFrequency() < 1 || getChannel() < 1) return -4; setPaddingBit(0); setPrivateBit(0); setCopyright(0); setOriginal(0); setFrameTimeLength(90000.0 / getSamplingFrequency()); switch (getLayer()) { case 1: setModeExtension(1); return 1; case 0x50: setModeExtension(2); return 0; case 0x55: setModeExtension(3); return 0; case 0x2000: setModeExtension(4); return 0; default: setModeExtension(0); } return 0; } private final String[] LSB_mode = { "F", "X" }; private final String[] compression = { "", "PCM", "MPEG", "MPEG-L3", "AC3" }; /** * display last wav header */ public String displayHeader() { return ("RIF" + LSB_mode[getLastID()] + ", " + (getLastModeExtension() > 0 ? compression[getLastModeExtension()] : "tag 0x" + Integer.toHexString(getLastLayer())) + ", " + getLastChannel() + "-ch, " + getLastSamplingFrequency() + "Hz, " + getLastSize() + "bit, " + (getLastBitrate() / 1000.0) + "kbps"); } }