/* * EQUAID3V2Frame.java * * Created on Jan 26, 2004 * * Copyright (C)2004,2005 Paul Grebenc * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * $Id: EQUAID3V2Frame.java,v 1.9 2005/02/06 18:11:15 paul Exp $ */ package org.blinkenlights.jid3.v2; import java.io.*; import java.util.*; import org.blinkenlights.jid3.*; import org.blinkenlights.jid3.io.*; import org.blinkenlights.jid3.util.*; /** * @author paul * * Frame containing equalization information for the playback of the track. */ public class EQUAID3V2Frame extends ID3V2Frame { private byte m_byAdjustmentBits; private Map m_oFrequencyToAdjustmentMap = null; /** Constructor. * * @param byAdjustmentBits the number of bits of precision each adjustment contains */ public EQUAID3V2Frame(byte byAdjustmentBits) { m_byAdjustmentBits = byAdjustmentBits; m_oFrequencyToAdjustmentMap = new HashMap(); } public EQUAID3V2Frame(InputStream oIS) throws ID3Exception { try { ID3DataInputStream oFrameDataID3DIS = new ID3DataInputStream(oIS); // adjustment bits m_byAdjustmentBits = (byte)oFrameDataID3DIS.readUnsignedByte(); m_oFrequencyToAdjustmentMap = new HashMap(); // read adjustments while (oFrameDataID3DIS.available() > 0) { // read increment/decrement choice, and frequency int iIncrementAndFrequency = oFrameDataID3DIS.readBEUnsigned16(); boolean bIncrement = (iIncrementAndFrequency & 32768) > 0; int iFrequency = (iIncrementAndFrequency & 32767); byte[] abyAdjustment = new byte[m_byAdjustmentBits/8]; oFrameDataID3DIS.readFully(abyAdjustment); Adjustment oAdjustment = new Adjustment(bIncrement, iFrequency, abyAdjustment); m_oFrequencyToAdjustmentMap.put(new Integer(iFrequency), oAdjustment); } } catch (Exception e) { throw new InvalidFrameID3Exception(e); } } public void accept(ID3Visitor oID3Visitor) { oID3Visitor.visitEQUAID3V2Frame(this); } /** Set the number of bits of precision for each adjustment. * * @param byAdjustmentBits the number of bits of precision */ public void setAdjustmentBits(byte byAdjustmentBits) { m_byAdjustmentBits = byAdjustmentBits; } /** Get the number of bits of precision for each adjustment. * * @return the number of bits of precision */ public byte getAdjustmentBits() { return m_byAdjustmentBits; } /** Set an adjustment for a given frequency. A new adjustment for a given frequency will * replace any existing one. * * @param oAdjustment the adjustment to be set */ public void setAdjustment(Adjustment oAdjustment) { m_oFrequencyToAdjustmentMap.put(new Integer(oAdjustment.getFrequency()), oAdjustment); } /** Get the currently set adjustment for a given frequency. * * @return the set adjustment for the given frequency, or null if no adjustment has been set for it * @throws ID3Exception if the frequency specified is outside the range from 0-32767Hz */ public Adjustment getAdjustment(int iFrequency) throws ID3Exception { if ((iFrequency < 0) || (iFrequency > 32767)) { throw new ID3Exception("Valid frequency range for EQUA adjustments is from 0-32767Hz."); } return (Adjustment)m_oFrequencyToAdjustmentMap.get(new Integer(iFrequency)); } /** Remove an existing adjustment. * * @param iFrequency the frequency of the adjustment to remove * @return the removed adjustment, or null if no adjustment was set at the specified frequency * @throws ID3Exception if the frequency specified is outside the range from 0-32767Hz */ public Adjustment removeAdjustment(int iFrequency) throws ID3Exception { if ((iFrequency < 0) || (iFrequency > 32767)) { throw new ID3Exception("Valid frequency range for EQUA adjustments is from 0-32767Hz."); } return (Adjustment)m_oFrequencyToAdjustmentMap.remove(new Integer(iFrequency)); } /** Get all adjustments which have been set. * * @return an array of all adjustments which have been set */ public Adjustment[] getAdjustments() { return (Adjustment[])m_oFrequencyToAdjustmentMap.values().toArray(new Adjustment[0]); } protected byte[] getFrameId() { return "EQUA".getBytes(); } public String toString() { // "equalization" is misspelled in the spec return "Equalization: Adjustment Bits = " + m_byAdjustmentBits; } protected void writeBody(ID3DataOutputStream oIDOS) throws IOException { // adjustment bits oIDOS.writeUnsignedByte(m_byAdjustmentBits); // adjustments Adjustment[] aoAdjustment = getAdjustments(); for (int i=0; i < aoAdjustment.length; i++) { aoAdjustment[i].write(oIDOS); } } public boolean equals(Object oOther) { if ((oOther == null) || (!(oOther instanceof EQUAID3V2Frame))) { return false; } EQUAID3V2Frame oOtherEQUA = (EQUAID3V2Frame)oOther; return ((m_byAdjustmentBits == oOtherEQUA.m_byAdjustmentBits) && m_oFrequencyToAdjustmentMap.equals(oOtherEQUA.m_oFrequencyToAdjustmentMap)); } /** Adjustment details for specific frequencies in EQUA frame. */ public class Adjustment { private boolean m_bIncrement; private int m_iFrequency; private byte[] m_abyAdjustment; /** Constructor. * * Note: Adjustment bytes must be provided explicitly, because they could be most of least significant * byte order. This is up to the implementor. * * @param bIncrement true if this adjustment is a volume boost, false otherwise * @param iFrequency the frequency to be adjusted (0-32767Hz) * @param abyAdjustment the adjustment bytes (note the number of bits must correspond to the adjustment * bits precision set for this frame, although the format for this frame is otherwise undefined) * @throws ID3Exception if the frequency specified is not in the valid range * @throws ID3Exception if the adjustment bytes are not provided */ public Adjustment(boolean bIncrement, int iFrequency, byte[] abyAdjustment) throws ID3Exception { m_bIncrement = bIncrement; if ((iFrequency < 0) || (iFrequency > 32767)) { throw new ID3Exception("The valid frequency range for EQUA frame is from 0 to 32767Hz."); } m_iFrequency = iFrequency; if ((abyAdjustment == null) || (abyAdjustment.length == 0)) { throw new ID3Exception("Adjustment bytes must be specified for EQUA frame."); } m_abyAdjustment = abyAdjustment; } /** Check if this adjustment is a volume boost. * * @return true is the adjustment is a volume boost, false otherwise */ public boolean isIncrement() { return m_bIncrement; } /** Check if this adjustment is a volume decrease. (Note this method is the negative value of isIncrement(). * * @return true if this adjustment is a volume decrease, false otherwise. */ public boolean isDecrement() { return !m_bIncrement; } /** Get the frequency to be adjusted. * * @return the frequency to be adjusted, in Hertz. */ public int getFrequency() { return m_iFrequency; } /** Get the frequency adjustment bytes. Note, the specific application needs to know how these * were written, to make any proper use of them. * * @return the frequency adjustment bytes */ public byte[] getAdjustment() { return m_abyAdjustment; } private void write(ID3DataOutputStream oIDOS) throws IOException { int iIncrementAndFrequency = m_iFrequency; if (m_bIncrement) { iIncrementAndFrequency |= 32768; } oIDOS.writeBEUnsigned16(iIncrementAndFrequency); oIDOS.write(m_abyAdjustment); } public boolean equals(Object oOther) { if ((oOther == null) || (!(oOther instanceof Adjustment))) { return false; } Adjustment oOtherAdjustment = (Adjustment)oOther; return ((m_bIncrement == oOtherAdjustment.m_bIncrement) && (m_iFrequency == oOtherAdjustment.m_iFrequency) && Arrays.equals(m_abyAdjustment, oOtherAdjustment.m_abyAdjustment)); } } }