Chapter 3. Digital Media File Operations Examples

This chapter contains sample applications that perform file operations using the digital media libraries.

Audio File Recognition

Example 3-1 contains a listing of afinfo.c, which performs audio file recognition.

Example 3-1. Audio File Recognition: afinfo.c


#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include <audiofile.h>
#include <audioutil.h>
#include <dmedia/dm_params.h>
#include <dmedia/dm_audio.h>

void myexit(int s) {
    if(s != 0) fprintf(stderr, “\n\nexited with %d.  oserror = %d\n”, s, oserror());
    exit(s);
}

#define MAX_AWARE_OPTS 5

int legalMarkID(int* ids, int nids, int id) {
    while(nids--)
        if(*ids++ == id) return 1;
    return 0;
}
typedef struct _maxamp {
    float max[4];
    int loc[4];
    int timetag;
} maxamp;

void dump(char *, int);

main(int argc, char *argv[]) {
    AFfilehandle handle;
    int verbose = 0;
    int sampfmt, sampwidth;
    int fileformat, compression;
    int channels;
    int byteorder, numMiscs, numInsts, numMarkers, numCompTypes;
    int numSupportedInsts, numSupportedInstParams;
    int numSupportedLoops, numSupportedMarkers;
    int defaultSampleFormat, defaultSampleWidth;
    int arg = 1;
    DMparams* formatParams;
    double slope, intercept, minclip, maxclip;
    if(argc < 2) {
        fprintf(stderr, “Usage:  %s [-v] filename1 [filename2 ...]\n”, argv[0]);
        myexit(0);
    }
    if(!strcmp(argv[arg], “-v”)) {
        verbose = 1;
        arg++;
    }
    mallopt(M_DEBUG, 1);
    for(; arg < argc; arg++) {
        char* filename = argv[arg];
        int* mids = NULL;
        int fd = 0;
        int track = AF_DEFAULT_TRACK;
        struct stat _stat;
        _stat.st_mode = 0;    /* reset */
        if(stat(filename, &_stat) < 0 || !(_stat.st_mode & S_IFREG))
            continue;
        fprintf(stderr, “\n**** %s Format Dump ****\n”, filename);
        handle = afOpenFile(filename, “r”, AF_NULL_FILESETUP);
        if(!handle) {
            int err;
            dmGetError(&err, NULL);
            if(err == AF_BAD_NOT_IMPLEMENTED && (fd = open(filename, 0)) > 0)
                fprintf(stderr, “Cannot read file (type %s)\n”,
                    (char *) afQueryPointer(AF_QUERYTYPE_FILEFMT, AF_QUERY_DESC,
                        afIdentifyNamedFD(fd, filename, NULL), 0, 0));
            if(fd > 0) close(fd);
            continue;
        }
        dmParamsCreate(&formatParams);
        afGetFormatParams(handle, track, formatParams);
        dmParamsDestroy(formatParams);
        fileformat = afGetFileFormat(handle, 0);
        fprintf(stderr, “File format: %s\n”,
            (char *) afQueryPointer(AF_QUERYTYPE_FILEFMT,
                                    AF_QUERY_NAME, fileformat, 0, 0));
        fprintf(stderr, “Duration: %f seconds\n”,
            afGetFrameCount(handle, track)/afGetRate(handle, track));
        fprintf(stderr, “Framecount: %d\n”,
            afGetFrameCount(handle, track));
        fprintf(stderr, “Data Offset: %d bytes\n”,
           afGetDataOffset(handle, track));
        fprintf(stderr, “Total Data Size: %d bytes\n”,
           afGetTrackBytes(handle, track));
        afGetSampleFormat(handle, track, &sampfmt, &sampwidth);
        fprintf(stderr, “Sample Format: %s, %d bits per sample\n”,
            sampfmt == AF_SAMPFMT_TWOSCOMP ? “2's complement”
            : sampfmt == AF_SAMPFMT_UNSIGNED ? “unsigned”
            : sampfmt == AF_SAMPFMT_FLOAT ? “floating point”
            : sampfmt == AF_SAMPFMT_DOUBLE ? “double-precision floating point” 
            : “unknown”,
            sampwidth);
        byteorder = afGetByteOrder(handle, track);
        fprintf(stderr, “Byte order is %s-endian\n”,
               byteorder == AF_BYTEORDER_BIGENDIAN ? “big” : “little”);
        fprintf(stderr, “Samprate: %f\n”, afGetRate(handle, track));
        fprintf(stderr, “Channel Count:  %d\n”,
        channels = afGetChannels(handle, track));
        fprintf(stderr, “Frame Size: %.4f bytes\n”,
           afGetFrameSize(handle, track, 0));
        afGetPCMMapping(handle, track, &slope, &intercept, &minclip, &maxclip);
        fprintf(stderr,
            “PCM Mapping:\t slope: %.4f  intercept: %.4f\n\t\tmin: %.4f
                              max: %.4f\n”, slope, intercept, minclip, maxclip);
        compression = afGetCompression(handle, track);
        fprintf(stderr, “Compression Type: %s\n”,
            (char *) afQueryPointer(AF_QUERYTYPE_COMPRESSION,
                                    AF_QUERY_NAME, compression, 0, 0));
        if(compression == AF_COMPRESSION_MPEG1) {
            int layer, target;
                AUpvlist pvlist = AUpvnew(MAX_AWARE_OPTS);
                AUpvsetparam  (pvlist, 0, AF_MPEG_PARAM_LAYER);
                AUpvsetvaltype(pvlist, 0, AU_PVTYPE_LONG);
                AUpvsetparam  (pvlist, 1, AF_MPEG_PARAM_BITRATE_TARGET);
                AUpvsetvaltype(pvlist, 1, AU_PVTYPE_LONG);
                afGetCompressionParams(handle, track,
                                        &compression, pvlist, 2);
            AUpvgetval(pvlist, 0, &layer);
            AUpvgetval(pvlist, 1, &target);
            fprintf(stderr, “\tCompression layer %d\n”,
                    layer==AF_MPEG_LAYER_I ? 1 : 2);
            fprintf(stderr, “\tBit Rate: %d BPS\n”, target);
            AUpvfree(pvlist);
        }
        else if(compression == AF_COMPRESSION_AWARE_MULTIRATE) {
            int policy, target;
            AUpvlist pvlist = AUpvnew(MAX_AWARE_OPTS);
            AUpvsetparam  (pvlist, 0, AF_AWARE_PARAM_BITRATE_POLICY);
            AUpvsetvaltype(pvlist, 0, AU_PVTYPE_LONG);
            afGetCompressionParams(handle, track,
                                   &compression, pvlist, 1);
            AUpvgetval(pvlist, 0, &policy);
            fprintf(stderr, “\tCompression bitrate policy: %s\n”,
               policy == AF_AWARE_FIXED_RATE ? “Fixed Rate”
               : policy == AF_AWARE_CONST_QUAL ? “Constant Quality”
               : policy == AF_AWARE_LOSSLESS ? “Lossless”
               : “Unknown!”);
            if(policy == AF_AWARE_FIXED_RATE) {
                    AUpvsetparam(pvlist, 0, AF_MPEG_PARAM_BITRATE_TARGET);
                    AUpvsetvaltype(pvlist, 0, AU_PVTYPE_LONG);
                    afGetCompressionParams(handle, track,
                                            &compression, pvlist, 1);
                AUpvgetval(pvlist, 0, &target);
                fprintf(stderr, “\tBit Rate: %d BPS\n”, target);
            }
            AUpvfree(pvlist);
        }
        defaultSampleFormat = afQueryLong(AF_QUERYTYPE_FILEFMT,
                AF_QUERY_SAMPLE_FORMATS, AF_QUERY_DEFAULT, fileformat, 0);
        defaultSampleWidth = afQueryLong(AF_QUERYTYPE_FILEFMT,
                AF_QUERY_SAMPLE_SIZES, AF_QUERY_DEFAULT, fileformat, 0);
        if(verbose) {
        fprintf(stderr, “Format's default sample format: %s  width: %d\n”,
            defaultSampleFormat == AF_SAMPFMT_TWOSCOMP ? “2's complement”
            : defaultSampleFormat == AF_SAMPFMT_UNSIGNED ? “unsigned”
            : defaultSampleFormat == AF_SAMPFMT_FLOAT ? “floating point”
            : defaultSampleFormat == AF_SAMPFMT_DOUBLE ?
                 “double-precision floating point” 
            : “unknown”,
            defaultSampleWidth);
        fprintf(stderr, “\n”);
        } /* verbose */

        numCompTypes = afQueryLong(AF_QUERYTYPE_FILEFMT,
                AF_QUERY_COMPRESSION_TYPES, AF_QUERY_VALUE_COUNT,
                fileformat, 0);
        if(verbose) {
        fprintf(stderr, “This format supports %d compression type(s)”,
                numCompTypes);
        if(numCompTypes > 0) {
            int i;
            int* types = (int *) afQueryPointer(AF_QUERYTYPE_FILEFMT,
                                                AF_QUERY_COMPRESSION_TYPES,
                                                  AF_QUERY_VALUES, fileformat,
                                                0);
            fprintf(stderr, “:\n”);
            for(i = 0; i < numCompTypes; i++)
                fprintf(stderr, “\t%s\n”,
                    (char *) afQueryPointer(AF_QUERYTYPE_COMPRESSION,
                                    AF_QUERY_NAME, types[i], 0, 0));
            free(types);
        }
        fprintf(stderr, “\n”);
        } /* verbose */

        if(verbose) {
        numSupportedMarkers = afQueryLong(AF_QUERYTYPE_MARK,
                AF_QUERY_MAX_NUMBER, fileformat, 0, 0);
        fprintf(stderr, “This format supports %d mark(s)”,
                numSupportedMarkers);
        fprintf(stderr, “\n”);
        } /* verbose */

        numMarkers = afGetMarkIDs(handle, track, NULL);
        if(numMarkers > 0) {
            int m;
            mids = (int *) calloc(numMarkers, sizeof(int));
            afGetMarkIDs(handle, track, mids);
            fprintf(stderr, “%d mark chunk(s) found:\n”, numMarkers);
            for(m = 0; m < numMarkers; m++) {
                fprintf(stderr,
                    “\tID: %d  name: \”%s\”\tcomment: \”%s\”\tposition: %d\n”,
                    mids[m], afGetMarkName(handle, track, mids[m]),
                    afGetMarkComment(handle, track, mids[m]),
                    afGetMarkPosition(handle, track, mids[m])
                );
            }
        }
        numSupportedInsts = afQueryLong(AF_QUERYTYPE_INST, AF_QUERY_MAX_NUMBER, 
                                    fileformat, 0, 0);
        numSupportedInstParams = afQueryLong(AF_QUERYTYPE_INSTPARAM,
                         AF_QUERY_ID_COUNT, fileformat,
                         0, 0);
        if(verbose) {
        fprintf(stderr, “This format supports %d inst chunk(s)”,
            numSupportedInsts);
        if(numSupportedInsts > 0) {
            numSupportedLoops = afQueryLong(AF_QUERYTYPE_INST,
                    AF_QUERY_LOOPS, AF_QUERY_MAX_NUMBER, fileformat, 0);
            fprintf(stderr, “, %d loop(s) per inst”, numSupportedLoops);
            fprintf(stderr, “, and %d inst param(s)”, numSupportedInstParams);
        }
        fprintf(stderr, “\n\n”);
        } /* verbose */

        numInsts = afGetInstIDs(handle, NULL);
        if(numInsts > 0) {
            int i;
            int* ids = (int *) calloc(numInsts, sizeof(int));
            afGetInstIDs(handle, ids);
            fprintf(stderr, “%d inst chunk(s) found:\n”, numInsts);
            for(i = 0; i < numInsts; i++) {
                int nLoops;
                int *loops = NULL;
                int instid = ids[i];
                fprintf(stderr, “\tid %d:\n”, instid);
                nLoops = afGetLoopIDs(handle, instid, NULL);
                if(nLoops > 0) {
                    int l;
                    fprintf(stderr, “\t%d loop(s):\n”, nLoops);
                    loops = (int *) calloc(nLoops, sizeof(int));
                    afGetLoopIDs(handle, instid, loops);
                    for(l = 0; l < nLoops; l++) {
                        int mode = afGetLoopMode(handle, instid, loops[l]);
                        int stID = afGetLoopStart(handle, instid, loops[l]);
                        int endID = afGetLoopEnd(handle, instid, loops[l]);
                        fprintf(stderr,
                          “\t\ttrackID: %d  mode: %s\tstartID: %d\tendID: %d\n”,
                            afGetLoopTrack(handle, instid, loops[l]),
                            mode == AF_LOOP_MODE_NOLOOP ? “ignored” :
                            mode == AF_LOOP_MODE_FORW ? “forward” :
                                “forward/backward”,
                            legalMarkID(mids, numMarkers, stID) ? stID : stID,
                            legalMarkID(mids, numMarkers, endID) ? endID : endID
                        );
                    }
                    cfree(loops);
                }
                if(numSupportedInstParams > 0) {
                    int i;
                    int *paramIDs = (int *) afQueryPointer(
                        AF_QUERYTYPE_INSTPARAM, AF_QUERY_IDS, fileformat, 0, 0);
                    fprintf(stderr, “\t%d paramID(s):\n”,
                            numSupportedInstParams);
                    for(i = 0; i < numSupportedInstParams; i++)
                        fprintf(stderr, “\t\tID: %d  Name: \”%s\”  Value: %d\n”,
                            paramIDs[i],
                            (char *) afQueryPointer(AF_QUERYTYPE_INSTPARAM,
                                            AF_QUERY_NAME,
                                            fileformat,
                                            paramIDs[i], 0),
                            afGetInstParamLong(handle, instid, paramIDs[i]));

                    cfree(paramIDs);
                }
            }
            cfree(ids);
        }
        if(verbose) {
        numMiscs = afQueryLong(AF_QUERYTYPE_MISC,
                    AF_QUERY_TYPE_COUNT, fileformat, 0, 0);
        fprintf(stderr, “This format supports %d MISC chunk type(s)”, numMiscs);
        if(numMiscs > 0) {
            int i;
            int* miscs = (int *) afQueryPointer(AF_QUERYTYPE_MISC,
                                                AF_QUERY_TYPES, fileformat,
                                                0, 0);
            fprintf(stderr, “:\n”);
            for(i = 0; i < numMiscs; i++)
                fprintf(stderr, “\tType: %d  Name: \”%s\”\n”,
                    miscs[i],
                    (char *) afQueryPointer(AF_QUERYTYPE_MISC,
                        AF_QUERY_NAME, miscs[i], 0, 0));
            free(miscs);
        }
        fprintf(stderr, “\n”);
        } /* verbose */
    
        numMiscs = afGetMiscIDs(handle, 0);
        if(numMiscs > 0) {
            int i;
            int* miscIDs = calloc(numMiscs, sizeof(int));
            int miscType, miscSize;
            char* miscBuf = NULL;
            char* typeName = “unknown”;
            afGetMiscIDs(handle, miscIDs);
            fprintf(stderr, “Misc chunks present in file:\n”);
            for(i = 0; i < numMiscs; i++) {
                miscType = afGetMiscType(handle, miscIDs[i]);
                miscSize = afGetMiscSize(handle, miscIDs[i]);
                typeName = (char *) afQueryPointer(AF_QUERYTYPE_MISC,
                           AF_QUERY_NAME,
                                       miscType, 0, 0);
                fprintf(stderr, “\tType: `%s' [%d]  Size: %d\n”,
                    typeName, miscType, miscSize);
                if(miscSize > 0) {
                    miscBuf = calloc(miscSize, 1);
                    afReadMisc(handle, miscIDs[i], miscBuf, miscSize);
                }
                if(miscType != AF_MISC_UNRECOGNIZED
                        && miscType != AF_MISC_APPL
                        && miscType != AF_MISC_MIDI
                        && miscType != AF_MISC_PCMMAP
                        && miscType != AF_MISC_IRCAM_PEAKAMP) {
                    char c;
                    char* m = miscBuf;
                    fprintf(stderr, “\tMisc chunk text:\n\t\t\””);
                    while(miscSize-- > 0) {
                        if(*m && isascii(c = *m++)) fprintf(stderr, “%c”, c);
                        else if(miscSize > 1) fprintf(stderr, “ “);
                    }
                    fprintf(stderr, “\”\n”);
                }
                else if (miscType == AF_MISC_IRCAM_PEAKAMP) {
                    if(miscSize >= sizeof(maxamp)) {
                        int c;
                        maxamp* amp = (maxamp *) miscBuf;
                        fprintf(stderr, “\tPeak amp information:\n”);
                        for(c = 0; c < channels; c++)
                            fprintf(stderr, “\t\tChan %d: peak: %f  loc: %d\n”,
                                c, amp->max[c], amp->loc[c]);
                        fprintf(stderr, “\tCreation time:  %d\n”, amp->timetag);
                    }
                else fprintf(stderr, “\t CORRUPTED MAXAMP: size %d < %d\n”,
                         miscSize, sizeof(maxamp));
                }
                else {
                    fprintf(stderr, “\tMisc chunk dump:\n\n”);
                    dump(miscBuf, miscSize);
                    fprintf(stderr, “\n\n”);
                }
                if(miscBuf) cfree(miscBuf);
                miscBuf = NULL;
            }
            cfree(miscIDs);
        }
        cfree(mids);
        afCloseFile(handle);
    }
}

int base = 16;

void dump(char *b, int bufsize) {
    unsigned char buf[17];
    int ct, bytes, remaining = bufsize, offset = -16,cu,az = 0;

    while (remaining) {
        bytes = remaining > 16 ? 16 : remaining;
        bcopy(b, buf, bytes);
        remaining -= bytes;
        ct = bytes;
        for (cu = 0; cu != ct; cu++)
            if (buf[cu])
                break;
        if (cu == 16)
            if (az) {
                if (az == 1)
                    fprintf(stderr, “*\n”);
                az = 2;
                offset += 16;
                continue;
            }
            else
                az = 1;
        else
            az = 0;
        buf[ct] = `\0';

        if (base==16)
          fprintf(stderr, “%08x: “,offset += 16);
        else if (base==8)
          fprintf(stderr, “%08o: “,offset += 16);
        else
          fprintf(stderr, “%08d: “,offset += 16);
                  
        for (cu = 0; cu != ct; cu++)
            fprintf(stderr, ((cu & 3) == 3) ? “%02x “ : “%02x”,(int) buf[cu]);
        fprintf(stderr, “%*s”,40-(ct*2+ct/4),””);
        for (cu = 0; cu != ct; cu++)
            if (buf[cu] < ` ` || buf[cu] >= `\x7f')
                buf[cu] = `.';
        fprintf(stderr, “%s\n”,buf);
    }
}