All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.monte.media.eightsvx.EightSVXDecoder Maven / Gradle / Ivy

There is a newer version: 1.1
Show newest version
/*
 * @(#)EightSVXDecoder.java  1.0  1999-10-19
 *
 * Copyright (c) 1999 Werner Randelshofer, Goldau, Switzerland.
 * All rights reserved.
 *
 * You may not use, copy or modify this file, except in compliance with the
 * license agreement you entered into with Werner Randelshofer.
 * For details see accompanying license terms.
 */
package org.monte.media.eightsvx;

import org.monte.media.AbortException;
import org.monte.media.ParseException;
import org.monte.media.iff.*;
import java.util.Vector;
import java.io.InputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.applet.AudioClip;

/**
 * Creates a collection of EightSVXAudioClip objects by
 * reading an IFF 8SVX file.
 *
 * 

8SVX Type Definitions *

 * #define ID_8SVX MakeID('8', 'S', 'V', 'X')
 * #define ID_VHDR MakeID('V', 'H', 'D', 'R')
 *
 * typedef LONG Fixed;     // A Fixed-point value, 16 bits to the left of
 * // the point and 16 to the right. A Fixed is a number
 * // of 2^16ths, i.e., 65536ths.
 * #define Unity 0x10000L  // Unity = Fixed 1.0 = maximum volume
 *
 * // sCompression: Choice of compression algorithm applied to the samples.
 * #define sCmpNone   0  // not compressed
 * #define sCmpFibDelta 1  // Fibonacci-delta encoding.
 * // Can be more kinds in the future.
 *
 * typedef struct {
 * ULONG oneShotHiSamples,   // # samples in the high octave 1-shot part
 * repeatHiSamples,   // # samples in the high octave repeat part
 * samplesPerHiCycle; // # samples/cycle in high octave, else 0
 * UWORD samplesPerSec;     // data sampling rate
 * UBYTE ctOctave,          // # octaves of waveform
 * sCompression;      // data compression technique used
 * Fixed volume;            // playback volume form 0 to Unity (full
 * // volume). Map this value into the output
 * // hardware's dynamic range.
 * } Voice8Header;
 *
 * #define ID_NAME MakeID('N', 'A', 'M', 'E')
 * // NAME chunk contains a CHAR[], the voice's name.
 *
 * #define ID_Copyright MakeID('(', 'c', ')', ' ')
 * // "(c) " chunk contains a CHAR[], the FORM's copyright notice.
 *
 * #define ID_AUTH MakeID('A', 'U', 'T', 'H')
 * // AUTH chunk contains a CHAR[], the author's name.
 *
 * #define ID_ANNO MakeID('A', 'N', 'N', 'O')
 * // ANNO chunk contains a CHAR[], author's text annotations.
 *
 * #define ID_ATAK MakeID('A', 'T', 'A', 'K')
 * #define ID_RLSE MakeID('R', 'L', 'S', 'E')
 *
 * typedef struct {
 * UWORD duration; // segment duration in milliseconds, > 0
 * Fixed dest;     // destination volume factor
 * } EGPoint;
 *
 * // ATAK and RLSE chunks contain an EGPoint[], piecewise-linear envelope.
 * // The envelope defines a function of time returning Fixed values. It's
 * // used to scale the nominal volume specified in the Voice8Header.
 *
 * #define RIGHT    4L
 * #define LEFT     2L
 * #define STEREO   6L
 *
 * #define ID_CHAN MakeID('C', 'H', 'A', 'N')
 * typedef sampletype LONG;
 *
 * #define ID_PAN MakeID('P', 'A', 'N', ' ')
 * typedef sposition Fixed; // 0 <= sposition <= Unity
 * // Unity refers to the maximum possible volume.
 *
 *
 * #define ID_BODY MakeID('B', 'O', 'D', 'Y')
 * typedef character BYTE; // 8 bit signed number, -128 thru 127.
 * // BODY chunk contains a BYTE[], array of audio data samples
 * 
* *

8SVX Regular Expression *

 * 8SVX       ::= "FORM" #{ "8SVX" VHDR [NAME] [Copyright] [AUTH] ANNO* [ATAK] [RLSE] [CHAN] [PAN] BODY }
 *
 * VHDR       ::= "VHDR" #{ Voice8Header }
 * NAME       ::= "NAME" #{ CHAR* } [0]
 * Copyright  ::= "(c) " #{ CHAR* } [0]
 * AUTH       ::= "AUTH" #{ CHAR* } [0]
 * ANNO       ::= "ANNO" #{ CHAR* } [0]
 *
 * ATAK       ::= "ATAK" #{ EGPoint* }
 * RLSE       ::= "RLSE" #{ EGPoint* }
 * CHAN       ::= "CHAN" #{ sampletype }
 * PAN        ::= "PAN " #{ sposition }
 * BODY       ::= "BODY" #{ BYTE* } [0]
 * 
* The token "#" represents a ckSize LONG count of the following {braced} data bytes. * E.g., a VHDR's "#" should equal sizeof(Voicd8Header). Literal items are shown in * "quotes", [square bracket items] are optional, and "*" means 0 ore more replications. * A sometimes-needed pad byte is shown als "[0]". * * @author Werner Randelshofer, Hausmatt 10, CH-6405 Goldau, Switzerland * @version 1.0 1999-10-19 */ public class EightSVXDecoder implements IFFVisitor { /* Constants */ public final static int EIGHT_SVX_ID = IFFParser.stringToID("8SVX"); public final static int VHDR_ID = IFFParser.stringToID("VHDR"); public final static int NAME_ID = IFFParser.stringToID("NAME"); public final static int COPYRIGHT_ID = IFFParser.stringToID("(c) "); public final static int ANNO_ID = IFFParser.stringToID("ANNO"); public final static int AUTH_ID = IFFParser.stringToID("AUTH"); //public final static int ATAK_ID = IFFParser.stringToID("ATAK"); //public final static int RLSE_ID = IFFParser.stringToID("RLSE"); public final static int CHAN_ID = IFFParser.stringToID("CHAN"); //public final static int PAN_ID = IFFParser.stringToID("PAN "); public final static int BODY_ID = IFFParser.stringToID("BODY"); /* Instance variables */ private Vector samples_ = new Vector(); private boolean within8SVXGroup_ = false; /* Constructors */ /** * Creates a new Audio Source from the specified InputStream. * * Pre condition * InputStream must contain IFF 8SVX data. * Post condition * - * Obligation * - * * @param in The input stream. */ public EightSVXDecoder(InputStream in) throws IOException { try { IFFParser iff = new IFFParser(); registerChunks(iff); iff.parse(in,this); } catch (ParseException e) { throw new IOException(e.toString()); } catch (AbortException e) { throw new IOException(e.toString()); } finally { in.close(); } } public EightSVXDecoder() { } /* Accessors */ public Vector getSamples() { return samples_; } /* Actions */ public void registerChunks(IFFParser iff) { iff.declareGroupChunk(EIGHT_SVX_ID,IFFParser.ID_FORM); iff.declarePropertyChunk(EIGHT_SVX_ID,VHDR_ID); iff.declarePropertyChunk(EIGHT_SVX_ID,NAME_ID); iff.declarePropertyChunk(EIGHT_SVX_ID,COPYRIGHT_ID); iff.declareCollectionChunk(EIGHT_SVX_ID,ANNO_ID); iff.declarePropertyChunk(EIGHT_SVX_ID,AUTH_ID); iff.declarePropertyChunk(EIGHT_SVX_ID,CHAN_ID); iff.declareDataChunk(EIGHT_SVX_ID,BODY_ID); } /** * Visits the start of an IFF GroupChunkExpression. * * Altough this method is declared as public it may only * be called from an IFFParser that has been invoked * by this class. * * Pre condition * Vector must not be null. * This method espects only FORM groups of type 8SVX. * Post condition * - * Obligation * - * * @param group Group Chunk to be visited. * @exception ParseException * When an error has been encountered. */ public void enterGroup(IFFChunk group) { if (group.getType() == EIGHT_SVX_ID) { within8SVXGroup_ = true;} } public void leaveGroup(IFFChunk group) { if (group.getType() == EIGHT_SVX_ID) { within8SVXGroup_ = false;} } public void visitChunk(IFFChunk group, IFFChunk chunk) throws ParseException { if (within8SVXGroup_) { if (chunk.getID() == BODY_ID ) // && group.getID() == EIGHT_SVX_ID) { if (group.getPropertyChunk(VHDR_ID) == null) { throw new ParseException("Sorry: Without 8SVX.VHDR-Chunk no sound possible"); } EightSVXAudioClip newSample = new EightSVXAudioClip(); decodeVHDR(newSample,group.getPropertyChunk(VHDR_ID)); decodeCHAN(newSample,group.getPropertyChunk(CHAN_ID)); decodeNAME(newSample,group.getPropertyChunk(NAME_ID)); decodeCOPYRIGHT(newSample,group.getPropertyChunk(COPYRIGHT_ID)); decodeAUTH(newSample,group.getPropertyChunk(COPYRIGHT_ID)); decodeANNO(newSample,group.getCollectionChunks(ANNO_ID)); decodeBODY(newSample,chunk); addAudioClip(newSample); } } } public void addAudioClip(AudioClip clip) { samples_.addElement(clip); } /** * The Voice 8 Header (VHDR) property chunk holds the playback parameters for the * sampled waveform. *
     * typedef LONG Fixed;     // A Fixed-point value, 16 bits to the left of
     * // the point and 16 to the right. A Fixed is a number
     * // of 2^16ths, i.e., 65536ths.
     * #define Unity 0x10000L  // Unity = Fixed 1.0 = maximum volume
     *
     * // sCompression: Choice of compression algorithm applied to the samples.
     * #define sCmpNone   0  // not compressed
     * #define sCmpFibDelta 1  // Fibonacci-delta encoding.
     * // Can be more kinds in the future.
     *
     * typedef struct {
     * ULONG oneShotHiSamples,   // # samples in the high octave 1-shot part
     * repeatHiSamples,   // # samples in the high octave repeat part
     * samplesPerHiCycle; // # samples/cycle in high octave, else 0
     * UWORD samplesPerSec;     // data sampling rate
     * UBYTE ctOctave,          // # octaves of waveform
     * sCompression;      // data compression technique used
     * Fixed volume;            // playback volume form 0 to Unity (full
     * // volume). Map this value into the output
     * // hardware's dynamic range.
     * } Voice8Header;
     * 
*/ protected void decodeVHDR(EightSVXAudioClip sample,IFFChunk chunk) throws ParseException { try { if (chunk != null) { MC68000InputStream in = new MC68000InputStream(new ByteArrayInputStream(chunk.getData())); sample.setOneShotHiSamples(in.readULONG()); sample.setRepeatHiSamples(in.readULONG()); sample.setSamplesPerHiCycle(in.readULONG()); sample.setSampleRate(in.readUWORD()); sample.setCtOctave(in.readUBYTE()); sample.setSCompression(in.readUBYTE()); sample.setVolume(in.readLONG()); } } catch (IOException e) { throw new ParseException("Error parsing 8SVX VHDR:" +e.getMessage()); } } protected void decodeCHAN(EightSVXAudioClip sample,IFFChunk chunk) throws ParseException { if (chunk != null) { sample.setSampleType(chunk.getData()[3]); } } protected void decodeNAME(EightSVXAudioClip sample,IFFChunk chunk) throws ParseException { if (chunk != null) { sample.setName(new String(chunk.getData())); } } protected void decodeCOPYRIGHT(EightSVXAudioClip sample,IFFChunk chunk) throws ParseException { if (chunk != null) { sample.setCopyright(new String(chunk.getData())); } } protected void decodeAUTH(EightSVXAudioClip sample,IFFChunk chunk) throws ParseException { if (chunk != null) { sample.setAuthor(new String(chunk.getData())); } } protected void decodeANNO(EightSVXAudioClip sample,IFFChunk[] chunks) throws ParseException { if (chunks != null) { for (int i=0; i < chunks.length; i++) { IFFChunk chunk = chunks[i]; sample.setRemark(sample.getRemark() + new String(chunk.getData())); } } } protected void decodeBODY(EightSVXAudioClip sample,IFFChunk chunk) throws ParseException { if (chunk != null) { byte[] data = chunk.getData(); sample.set8SVXBody(data); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy