[comp.sys.amiga] IFF News

carolyn@cbmvax.cbm.UUCP (Carolyn Scheppner) (11/20/86)

                            ========                       
                            IFF News
                            ========
              
             Carolyn Scheppner  Amiga Technical Support

   In mid-September, we printed/duped a new batch of IFF docs and disks.
The new batch is labeled "September 19, 1986".  There were a few fixes
and changes which I will describe for the benefit of those who have
the April 30, 1986 release.  In addition, I recently received some
new material (SMUS.h, 8SVX.h, Read8svx.c) from EA.  Listings of these
new files are attached.


FIXES/CHANGES INCORPORATED IN SEPT 30 DOCS/DISK
===============================================
  
Document
   1. Errata/Addenda from previous printing were incorporated.
   2. New listing for SeeILBM.  

Disk
   1. The source for the readpict.c module no longer "contains binary".
      The problem was a control character in a comment.
      (If you want to find it using Emacs, search for the word "via"
       in a comment line.  I think the control character is in the
       word "handle" in the same line)
   2. Revised source for SeeILBM.

   The revisions to SeeILBM were:

   - Polling eliminated.  It now Waits for mouse activity.
         
   - Checking of window->MouseX and MouseY replaced with saving and
     checking of msg->MouseX and MouseY.  This makes little difference
     to SeeILBM but is necessary when SeeILBM is used as a base for
     a program that can't handle its messages immediately.
     You want to know where the mouse was when the button was PRESSED,
     not where it is when you HANDLE the message.

   - Handling of ILBMFrames modified to use only one global frame.
     It should now work properly with LISTs and PROPs but I don't
     have any to try it out on.



NEW INFORMATION SINCE SEPT 30 RELEASE
=====================================

1.  EA just told me that they have defined two more SID values in
    SMUS:

           (SID value)                   (Next data byte)

       #define SID_Clef  135      0=treble,1=bass,2=alto,3=tenor
       #define SID_Tempo 136      beats per minute (0-255)

    These values are also defined in the attached SMUS.h header file.

2.  I recently discovered that the IFF object modules on our
    distribution disk were compiled without disabling stack
    checking.  This is fine if you're linking with LStartup.obj.
    However, if you plan to link with AStartup ... Amiga.lib, LC.lib,
    you'll have to first recompile the IFF modules using the -v
    flag on LC2.

3.  I am expecting some new FORM and Chunk descriptions from several
    third-party developers.  I'll let you know when I get them.
    Remember that ALL NEW IFF FORMS and Chunks should be registered
    with me.  This will hopefully avoid name conflicts and unneccesary
    duplication of existing formats. 

    Some suggestions when designing new FORMs and chunks
    
       - Read the docs carefully and see if an existing chunk,
         FORM, or CAT/LIST of FORMS will fill your needs
    
       - If you decide that you need a NEW form or chunk,
         call me first to find out if a suitable new one
         has been registered.
    
       - If you need to design a new form or chunk, follow
         the guidelines in the EA specs.  Think ahead when
         designing a chunk.  An IFF FORM or Chunk does not
         become a standard just because it's "IFF".  Try to
         design something that will be useful to other
         applications and future applications of your own.

         If possible, discuss your form/chunk ideas with
         other programmers.  A bulletin board is a good
         place to get ideas from programmers with a
         variety of interests.  Try to include variables
         for pertinent features even if you are not
         supporting them in your current application.

      -  Include a couple of pad variables in your chunk
         for future expansion.
         Make your chunks an even size if possible because
         some home-brew readers may choke on the required
         pad byte 0 after an odd-size chunk.
  
      -  Remember to register the form/chunk with me.  Do this
         as early as possible in your program development
         so that it will be possible to work in suggested
         modifications or additions. 
       
         The information I need includes:

          - Your name, address, phone number
          - Name and description of your product, and information
            on any other commercial or public domain software
            that supports your form/chunks
          - Names of form/chunks and itemized description
            of their contents. (see IFF specs for examples)
          - Purposes of the form/chunks
          

WHERE TO REGISTER FORMS/CHUNKS
==============================

         US MAIL   Carolyn Scheppner
                   Software Tech Support
                   CBM
                   1200 Wilson Drive
                   West Chester, PA  19380
         
         PHONE     215-431-9180
         UUCP      ...{allegra,caip,ihnp4,seismo}!cbmvax!carolyn
 

HOW TO ORDER IFF DOCS AND DISK
==============================
   
   The IFF specs and disk containing docs, source, Lattice object, and
some executable examples is available for $20 from

         Kim Montgomery / Software Tech Support
         Commodore Business Machines
         1200 Wilson Drive
         West Chester, PA.  19380

   Make the check out to Commodore Business Machines, be sure to
include your name and address, and ask for "IFF docs and disk".
     

-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Carolyn Scheppner -- CBM   >>Amiga Technical Support<<
                     UUCP  ...{allegra,caip,ihnp4,seismo}!cbmvax!carolyn 
                     PHONE 215-431-9180
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

carolyn@cbmvax.cbm.UUCP (Carolyn Scheppner) (11/20/86)

#ifndef SMUS_H
#define SMUS_H
/*----------------------------------------------------------------------*
 * SMUS.H  Definitions for Simple MUSical score.   2/12/86
 *
 * By Jerry Morrison and Steve Hayes, Electronic Arts.
 * This software is in the public domain.
 *
 * This version for the Commodore-Amiga computer.
 *----------------------------------------------------------------------*/
#ifndef COMPILER_H
#include "iff/compiler.h"
#endif

#include "iff/iff.h"

#define ID_SMUS      MakeID('S', 'M', 'U', 'S')
#define ID_SHDR      MakeID('S', 'H', 'D', 'R')
#define ID_NAME      MakeID('N', 'A', 'M', 'E')
#define ID_Copyright MakeID('(', 'c', ')', ' ')
#define ID_AUTH      MakeID('A', 'U', 'T', 'H')
#define ID_ANNO      MakeID('A', 'N', 'N', 'O')

#define ID_INS1      MakeID('I', 'N', 'S', '1')
#define ID_TRAK      MakeID('T', 'R', 'A', 'K')

/* ---------- SScoreHeader ---------------------------------------------*/
typedef struct {
    UWORD tempo;	/* tempo, 128ths quarter note/minute */
    UBYTE volume;	/* playback volume 0 through 127 */
    UBYTE ctTrack;	/* count of tracks in the score */
    } SScoreHeader;

/* ---------- NAME -----------------------------------------------------*/
/* NAME chunk contains a CHAR[], the musical score's name. */

/* ---------- Copyright (c) --------------------------------------------*/
/* "(c) " chunk contains a CHAR[], the FORM's copyright notice. */

/* ---------- AUTH -----------------------------------------------------*/
/* AUTH chunk contains a CHAR[], the name of the score's author. */

/* ---------- ANNO -----------------------------------------------------*/
/* ANNO chunk contains a CHAR[], the author's text annotations. */

/* ---------- INS1 -----------------------------------------------------*/
/* Constants for the RefInstrument's "type" field. */
#define INS1_Name  0	/* just use the name; ignore data1, data2 */
#define INS1_MIDI  1	/* <data1, data2> = MIDI <channel, preset> */

typedef struct {
    UBYTE iRegister;	/* set this instrument register number */
    UBYTE type;		/* instrument reference type (see above) */
    UBYTE data1, data2;	/* depends on the "type" field */
    char name[60];	/* instrument name */
    } RefInstrument;

/* ---------- TRAK -----------------------------------------------------*/
/* TRAK chunk contains an SEvent[]. */

/* SEvent: Simple musical event. */
typedef struct {
    UBYTE sID;		/* SEvent type code */
    UBYTE data;		/* sID-dependent data */
    } SEvent;

/* SEvent type codes "sID". */
#define SID_FirstNote     0
#define SID_LastNote    127	/* sIDs in the range SID_FirstNote through
				 * SID_LastNote (sign bit = 0) are notes. The
				 * sID is the MIDI tone number (pitch). */
#define SID_Rest        128	/* a rest; same data format as a note. */

#define SID_Instrument  129	/* set instrument number for this track. */
#define SID_TimeSig     130	/* set time signature for this track. */
#define SID_KeySig	131	/* set key signature for this track. */
#define SID_Dynamic	132	/* set volume for this track. */
#define SID_MIDI_Chnl	133	/* set MIDI channel number (sequencers) */
#define SID_MIDI_Preset	134	/* set MIDI preset number (sequencers) */
#define SID_Clef        135     /* inline clef change. 
                                 * 0=Treble, 1=Bass, 2=Alto, 3=Tenor. */
#define SID_Tempo       136     /* Inline tempo change in beats per minute.*/

/* SID values 144 through 159: reserved for Instant Music SEvents. */

/* The remaining sID values up through 254: reserved for future
 * standardization. */
#define SID_Mark        255	/* SID reserved for an end-mark in RAM. */

/* ---------- SEvent FirstNote..LastNote or Rest -----------------------*/
typedef struct {
    unsigned tone     :8,	/* MIDI tone number 0 to 127; 128 = rest */
             chord    :1,	/* 1 = a chorded note */
             tieOut   :1,	/* 1 = tied to the next note or chord */
             nTuplet  :2,	/* 0 = none, 1 = triplet, 2 = quintuplet,
				 * 3 = septuplet */
             dot      :1,	/* dotted note; multiply duration by 3/2 */
             division :3;	/* basic note duration is 2**-division:
				 * 0 = whole note, 1 = half note, 2 = quarter
				 * note, ... 7 = 128th note */
    } SNote;

/* Warning: An SNote is supposed to be a 16-bit entity.
 * Some C compilers will not pack bit fields into anything smaller
 * than an int. So avoid the actual use of this type unless you are certain
 * that the compiler packs it into a 16-bit word.
 */

/* You may get better object code by masking, ORing, and shifting using the
 * following definitions rather than the bit-packed fields, above. */
#define noteChord  (1<<7)	/* note is chorded to next note */

#define noteTieOut (1<<6)	/* note/chord is tied to next note/chord */

#define noteNShift 4			/* shift count for nTuplet field */
#define noteN3     (1<<noteNShift)	/* note is a triplet */
#define noteN5     (2<<noteNShift)	/* note is a quintuplet */
#define noteN7     (3<<noteNShift)	/* note is a septuplet */
#define noteNMask  noteN7		/* bit mask for the nTuplet field */

#define noteDot    (1<<3)		/* note is dotted */

#define noteDShift 0			/* shift count for division field */
#define noteD1     (0<<noteDShift)	/* whole note division */
#define noteD2     (1<<noteDShift)	/* half note division */
#define noteD4     (2<<noteDShift)	/* quarter note division */
#define noteD8     (3<<noteDShift) 	/* eighth note division */
#define noteD16    (4<<noteDShift) 	/* sixteenth note division */
#define noteD32    (5<<noteDShift) 	/* thirty-secondth note division */
#define noteD64    (6<<noteDShift) 	/* sixty-fourth note division */
#define noteD128   (7<<noteDShift) 	/* 1/128 note division */
#define noteDMask  noteD128		/* bit mask for the division field */

#define noteDurMask 0x3F		/* bit mask for all duration fields
					 * division, nTuplet, dot */

/* Field access: */
#define IsChord(snote)	(((UWORD)snote) & noteChord)
#define IsTied(snote) 	(((UWORD)snote) & noteTieOut)
#define NTuplet(snote) 	((((UWORD)snote) & noteNMask) >> noteNShift)
#define IsDot(snote) 	(((UWORD)snote) & noteDot)
#define Division(snote) ((((UWORD)snote) & noteDMask) >> noteDShift)

/* ---------- TimeSig SEvent -------------------------------------------*/
typedef struct {
    unsigned type     :8,	/* = SID_TimeSig */
             timeNSig :5,	/* time signature "numerator" timeNSig + 1 */
             timeDSig :3;	/* time signature "denominator" is
				 * 2**timeDSig: 0 = whole note, 1 = half
				 * note, 2 = quarter note, ...
				 * 7 = 128th note */
    } STimeSig;

#define timeNMask  0xF8		/* bit mask for timeNSig field */
#define timeNShift 3		/* shift count for timeNSig field */

#define timeDMask  0x07		/*  bit mask for timeDSig field */

/* Field access: */
#define TimeNSig(sTime)  ((((UWORD)sTime) & timeNMask) >> timeNShift)
#define TimeDSig(sTime)   (((UWORD)sTime) & timeDMask)

/* ---------- KeySig SEvent --------------------------------------------*/
/* "data" value 0 = Cmaj; 1 through 7 = G,D,A,E,B,F#,C#;
 * 8 through 14 = F,Bb,Eb,Ab,Db,Gb,Cb.					*/

/* ---------- Dynamic SEvent -------------------------------------------*/
/* "data" value is a MIDI key velocity 0..127. */


/* ---------- SMUS Reader Support Routines -----------------------------*/

/* Just call this to read a SHDR chunk. */
#define GetSHDR(context, ssHdr)  \
    IFFReadBytes(context, (BYTE *)ssHdr, sizeof(SScoreHeader))

/* ---------- SMUS Writer Support Routines -----------------------------*/

/* Just call this to write a SHDR chunk. */
#define PutSHDR(context, ssHdr)  \
    PutCk(context, ID_SHDR, sizeof(SScoreHeader), (BYTE *)ssHdr)

#endif
-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Carolyn Scheppner -- CBM   >>Amiga Technical Support<<
                     UUCP  ...{allegra,caip,ihnp4,seismo}!cbmvax!carolyn 
                     PHONE 215-431-9180
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

carolyn@cbmvax.cbm.UUCP (Carolyn Scheppner) (11/20/86)

#ifndef EIGHTSVX_H
#define EIGHTSVX_H
/*-----------------------------------------------------------------------*
 * 8SVX.H  Definitions for 8-bit sampled voice (VOX).   2/10/86
 *
 * By Jerry Morrison and Steve Hayes, Electronic Arts.
 * This software is in the public domain.
 *
 * This version for the Commodore-Amiga computer.
 *----------------------------------------------------------------------*/
#ifndef COMPILER_H
#include "iff/compiler.h"
#endif

#include "iff/iff.h"

#define ID_8SVX      MakeID('8', 'S', 'V', 'X')
#define ID_VHDR      MakeID('V', 'H', 'D', 'R')
#define ID_NAME      MakeID('N', 'A', 'M', 'E')
#define ID_Copyright MakeID('(', 'c', ')', ' ')

#define ID_AUTH      MakeID('A', 'U', 'T', 'H')
#define ID_ANNO      MakeID('A', 'N', 'N', 'O')

#define ID_BODY      MakeID('B', 'O', 'D', 'Y')

#define ID_ATAK      MakeID('A', 'T', 'A', 'K')
#define ID_RLSE      MakeID('R', 'L', 'S', 'E')

/* ---------- Voice8Header ---------------------------------------------*/
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 (Appendix C) */
				/* Could 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,		/* # of octaves of waveforms */
          sCompression;		/* data compression technique used */
    Fixed volume;		/* playback nominal volume from 0 to Unity
				 * (full volume). Map this value into
				 * the output hardware's dynamic range.
				 */
    } Voice8Header;

/* ---------- NAME -----------------------------------------------------*/
/* NAME chunk contains a CHAR[], the voice's name. */

/* ---------- Copyright ------------------------------------------------*/
/* "(c) " chunk contains a CHAR[], the FORM's copyright notice. */

/* ---------- AUTH -----------------------------------------------------*/
/* AUTH chunk contains a CHAR[], the author's name. */

/* ---------- ANNO -----------------------------------------------------*/
/* ANNO chunk contains a CHAR[], the author's text annotations. */

/* ---------- Envelope ATAK & RLSE -------------------------------------*/
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.
 */

/* ---------- BODY -----------------------------------------------------*/
/* BODY chunk contains a BYTE[], array of audio data samples. */
/* (8-bit signed numbers, -128 through 127.) */


/* ---------- 8SVX Reader Support Routines -----------------------------*/

/* Just call this macro to read a VHDR chunk. */
#define GetVHDR(context, vHdr)  \
    IFFReadBytes(context, (BYTE *)vHdr, sizeof(Voice8Header))


/* ---------- 8SVX Writer Support Routines -----------------------------*/

/* Just call this macro to write a VHDR chunk. */
#define PutVHDR(context, vHdr)  \
    PutCk(context, ID_VHDR, sizeof(Voice8Header), (BYTE *)vHdr)

#endif
-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Carolyn Scheppner -- CBM   >>Amiga Technical Support<<
                     UUCP  ...{allegra,caip,ihnp4,seismo}!cbmvax!carolyn 
                     PHONE 215-431-9180
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

carolyn@cbmvax.cbm.UUCP (Carolyn Scheppner) (11/20/86)

/** Read8SVX.c ************************************************************** 
 * 
 * Read a sound sample from an IFF file.  21Jan85 
 * 
 * By Steve Hayes, Electronic Arts. 
 * This software is in the public domain. 
 * 
 ****************************************************************************/ 
 
#include "exec/types.h" 
#include "exec/exec.h" 
#include "libraries/dos.h" 
#include "iff/8svx.h" 
 
/* Message strings for IFFP codes. */ 
char MsgOkay[]        = { "(IFF_OKAY) No FORM 8SVX in the file." }; 
char MsgEndMark[]     = { "(END_MARK) How did you get this message?" }; 
char MsgDone[]        = { "(IFF_DONE) All done."}; 
char MsgDos[]         = { "(DOS_ERROR) The DOS returned an error." }; 
char MsgNot[]         = { "(NOT_IFF) Not an IFF file." }; 
char MsgNoFile[]      = { "(NO_FILE) No such file found." }; 
char MsgClientError[] = { "(CLIENT_ERROR) Read8SVX bug or insufficient RAM."}; 
char MsgForm[]        = { "(BAD_FORM) A malformed FORM 8SVX." }; 
char MsgShort[]       = { "(SHORT_CHUNK) A malformed FORM 8SVX." }; 
char MsgBad[]         = { "(BAD_IFF) A mangled IFF file." }; 
 
/* THESE MUST APPEAR IN RIGHT ORDER!! */ 
char *IFFPMessages[-LAST_ERROR+1] = { 
    /*IFF_OKAY*/  MsgOkay, 
    /*END_MARK*/  MsgEndMark, 
    /*IFF_DONE*/  MsgDone, 
    /*DOS_ERROR*/ MsgDos, 
    /*NOT_IFF*/   MsgNot, 
    /*NO_FILE*/   MsgNoFile, 
    /*CLIENT_ERROR*/ MsgClientError, 
    /*BAD_FORM*/  MsgForm, 
    /*SHORT_CHUNK*/  MsgShort, 
    /*BAD_IFF*/   MsgBad 
    }; 
 
typedef struct { 
   ClientFrame clientFrame; 
   UBYTE foundVHDR; 
   UBYTE pad1; 
   Voice8Header sampHdr; 
   } SVXFrame; 
 
 
/* NOTE: For a simple version of this program, set Fancy to 0. 
 * That'll compile a program that skips all LISTs and PROPs in the input 
 * file. It will look in CATs for FORMs 8SVX. That's suitable for most uses. 
 * 
 * For a fancy version that handles LISTs and PROPs, set Fancy to 1. */ 
 
#define Fancy  1 
 
BYTE *buf; 
int szBuf; 
 
/** DoSomethingWithSample() **********************************************
 * 
 * Interface to Amiga sound driver. 
 * 
 *************************************************************************/
DoSomethingWithSample(sampHdr)  Voice8Header *sampHdr;  { 
    BYTE *t; 
    printf("\noneShotHiSamples=%ld", sampHdr->oneShotHiSamples); 
    printf("\nrepeatHiSamples=%ld", sampHdr->repeatHiSamples); 
    printf("\nsamplesPerHiCycle=%ld", sampHdr->samplesPerHiCycle); 
    printf("\nsamplesPerSec=%ld", sampHdr->samplesPerSec); 
    printf("\nctOctave=%ld", sampHdr->ctOctave); 
    printf("\nsCompression=%ld", sampHdr->sCompression); 
    printf("\nvolume=0x%lx", sampHdr->volume); 
    /* Decompress, if needed. */ 
    if (sampHdr->sCompression) { 
        t = (BYTE *)AllocMem(szBuf<<1, MEMF_CHIP); 
        DUnpack(buf, szBuf, t); 
        FreeMem(buf, szBuf); 
        buf = t; 
        szBuf <<= 1; 
        }; 
    printf("\nData = %3ld %3ld %3ld %3ld %3ld %3ld %3ld %3ld",  
           buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7]); 
    printf("\n       %3ld %3ld %3ld %3ld %3ld %3ld %3ld %3ld ...\n",  
           buf[8+0],buf[8+1],buf[8+2],buf[8+3],buf[8+4],buf[8+5],
           buf[8+6],buf[8+ 7]); 
    } 
 
/** ReadBODY() ***********************************************************
 * 
 * Read a BODY into RAM.  
 * 
 *************************************************************************/
IFFP ReadBODY(context)  GroupContext *context;  { 
    IFFP iffp; 
 
    szBuf  = ChunkMoreBytes(context); 
    buf  = (BYTE *)AllocMem(szBuf, MEMF_CHIP); 
    if (buf == NULL) 
        iffp = CLIENT_ERROR; 
    else 
        iffp = IFFReadBytes(context, (BYTE *)buf, szBuf); 
    CheckIFFP(); 
    } 
 
/** GetFo8SVX() **********************************************************
 * 
 * Called via ReadSample to handle every FORM encountered in an IFF file. 
 * Reads FORMs 8SVX and skips all others. 
 * Inside a FORM 8SVX, it reads BODY. It complains if it 
 * doesn't find an VHDR before the BODY. 
 * 
 * [TBD] We could read and print out any NAME and "(c) " chunks. 
 * 
 *************************************************************************/
IFFP GetFo8SVX(parent)  GroupContext *parent;  { 
   /*compilerBug register*/ IFFP iffp; 
   GroupContext formContext; 
   SVXFrame smusFrame;          /* only used for non-clientFrame fields.*/ 
 
   if (parent->subtype != ID_8SVX) 
      return(IFF_OKAY); /* just continue scaning the file */ 
 
   smusFrame = *(SVXFrame *)parent->clientFrame; 
   iffp = OpenRGroup(parent, &formContext); 
   CheckIFFP(); 
 
   do switch (iffp = GetFChunkHdr(&formContext)) { 
      case ID_VHDR: { 
        smusFrame.foundVHDR = TRUE; 
        iffp = GetVHDR(&formContext, &smusFrame.sampHdr); 
        break; } 
      case ID_BODY: { 
        if (!smusFrame.foundVHDR) 
            iffp = BAD_FORM;            /* Need an VHDR chunk first! */ 
        else iffp = ReadBODY(&formContext); 
        break; } 
      case END_MARK: { 
        if (!smusFrame.foundVHDR) 
            iffp = BAD_FORM; 
        else 
            iffp = IFF_DONE; 
        break; } 
      } while (iffp >= IFF_OKAY);  /* loop if valid ID of ignored chunk or a 
                                * subroutine returned IFF_OKAY (no errors).*/ 
 
    if (iffp != IFF_DONE)  return(iffp); 
 
    /* If we get this far, there were no errors. */ 
    CloseRGroup(&formContext); 
    DoSomethingWithSample(&smusFrame.sampHdr); 
    FreeMem(buf, szBuf); 
    return(iffp); 
    } 
 
/** Notes on extending GetFo8SVX ****************************************
 * 
 * To read more kinds of chunks, just add clauses to the switch statement. 
 * To read more kinds of property chunks (like NAME) add clauses to 
 * the switch statement in GetPr8SVX, too. 
 * 
 ************************************************************************/
 
/** GetPr8SVX() *********************************************************
 * 
 * Called via ReadSample to handle every PROP encountered in an IFF file. 
 * Reads PROPs 8SVX and skips all others. 
 * 
 *************************************************************************/
#if Fancy 
IFFP GetPr8SVX(parent)  GroupContext *parent;  { 
   /*compilerBug register*/ IFFP iffp; 
   GroupContext propContext; 
   SVXFrame *svxFrame = (SVXFrame *)parent->clientFrame; /* Subclass */ 
 
   if (parent->subtype != ID_8SVX) 
      return(IFF_OKAY); /* just continue scaning the file */ 
 
   iffp = OpenRGroup(parent, &propContext); 
   CheckIFFP(); 
 
   do switch (iffp = GetPChunkHdr(&propContext)) { 
      case ID_VHDR: { 
        svxFrame->foundVHDR = TRUE; 
        iffp = GetVHDR(&propContext, &svxFrame->sampHdr); 
        break; } 
      } while (iffp >= IFF_OKAY);  /* loop if valid ID of ignored chunk or a 
                              * subroutine returned IFF_OKAY (no errors).*/ 
 
   CloseRGroup(&propContext); 
   return(iffp == END_MARK ? IFF_OKAY : iffp); 
   } 
#endif 
 
/** GetLi8SVX() **********************************************************
 * 
 * Called via ReadSample to handle every LIST encountered in an IFF file. 
 * 
 *************************************************************************/
#if Fancy 
IFFP GetLi8SVX(parent)  GroupContext *parent;  { 
    SVXFrame newFrame;  /* allocate a new Frame */ 
 
    newFrame = *(SVXFrame *)parent->clientFrame;  /* copy parent frame */ 
 
    return( ReadIList(parent, (ClientFrame *)&newFrame) ); 
    } 
#endif 
 
/** ReadSample() **********************************************************
 * 
 * Read IFF 8SVX, given a file handle open for reading.
 * 
 *************************************************************************/
IFFP ReadSample(file)  LONG file;  { 
   SVXFrame sFrame;     /* Top level "client frame".*/ 
   IFFP iffp = IFF_OKAY; 
 
#if Fancy 
   sFrame.clientFrame.getList = GetLi8SVX; 
   sFrame.clientFrame.getProp = GetPr8SVX; 
#else 
   sFrame.clientFrame.getList = SkipGroup; 
   sFrame.clientFrame.getProp = SkipGroup; 
#endif 
   sFrame.clientFrame.getForm = GetFo8SVX; 
   sFrame.clientFrame.getCat  = ReadICat ; 
 
   /* Initialize the top-level client frame's property settings to the 
    * program-wide defaults. This example just records that we haven't read 
    * any VHDR properties yet. 
    * If you want to read another property, init it's fields in sFrame. */ 
   sFrame.foundVHDR = FALSE; 
   sFrame.pad1      = 0; 
 
   iffp = ReadIFF(file, (ClientFrame *)&sFrame); 
 
   return(iffp); 
   } 
 
/** main0() **************************************************************/
void main0(filename)  char *filename;  { 
    LONG file; 
    IFFP iffp = NO_FILE; 
    file = Open(filename, MODE_OLDFILE); 
    if (file) 
        iffp = ReadSample(file); 
    Close(file); 
    printf(" %s\n", IFFPMessages[-iffp]); 
    } 
 
/** main() ***************************************************************/
void main(argc, argv)  int argc;  char **argv;  { 
    printf("Reading file '%s' ...", argv[1]); 
    if (argc < 2) 
        printf("\nfilename required\n"); 
    else 
        main0(argv[1]); 
    } 

-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Carolyn Scheppner -- CBM   >>Amiga Technical Support<<
                     UUCP  ...{allegra,caip,ihnp4,seismo}!cbmvax!carolyn 
                     PHONE 215-431-9180
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

carolyn@cbmvax.cbm.UUCP (Carolyn Scheppner) (11/20/86)

/* DUnpack.c --- Fibonacci Delta decompression by Steve Hayes */

#include <exec/types.h>

/* Fibonacci delta encoding for sound data */
BYTE codeToDelta[16] = {-34,-21,-13,-8,-5,-3,-2,-1,0,1,2,3,5,8,13,21};

/* Unpack Fibonacci-delta encoded data from n byte source
 * buffer into 2*n byte dest buffer, given initial data
 * value x.  It returns the lats data value x so you can
 * call it several times to incrementally decompress the data.
 */

BYTE D1Unpack(source,n,dest,x)
BYTE source[], dest[];
LONG n;
BYTE x;
   {
   BYTE d;
   LONG i, lim;

   lim = n << 1;
   for (i=0; i < lim; ++i)
      {
      /* Decode a data nibble, high nibble then low nibble */
      d = source[i >> 1];    /* get a pair of nibbles */
      if (i & 1)             /* select low or high nibble */
         d &= 0xf;           /* mask to get the low nibble */
      else
         d >>= 4;            /* shift to get the high nibble */
      x += codeToDelta[d];   /* add in the decoded delta */
      dest[i] = x;           /* store a 1 byte sample */
      }
   return(x);
   }

/* Unpack Fibonacci-delta encoded data from n byte
 * source buffer into 2*(n-2) byte dest buffer.
 * Source buffer has a pad byte, an 8-bit initial
 * value, followed by n-2 bytes comprising 2*(n-2)
 * 4-bit encoded samples.
 */

void DUnpack(source, n, dest)
BYTE source[], dest[];
LONG n;
   {
   D1Unpack(source+2, n-2, dest, source[1]);
   }

-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Carolyn Scheppner -- CBM   >>Amiga Technical Support<<
                     UUCP  ...{allegra,caip,ihnp4,seismo}!cbmvax!carolyn 
                     PHONE 215-431-9180
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=

carolyn@cbmvax.cbm.UUCP (Carolyn Scheppner) (11/20/86)

Example linkage for Read8svx.c.  Note that iffr.o is the object of
one of the standard IFF reader modules.  For this link, all modules
must be compiled with the -v flag on LC2.

FROM     LIB:AStartup.obj, Read8svx.o, dUnpack.o, iffr.o
LIBRARY  LIB:Amiga.lib
TO       Read8svx


-- 
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
Carolyn Scheppner -- CBM   >>Amiga Technical Support<<
                     UUCP  ...{allegra,caip,ihnp4,seismo}!cbmvax!carolyn 
                     PHONE 215-431-9180
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=