Esempio n. 1
0
/*
 * This was the original reading function that did not allow for
 * preselecting time. Should be save to remove now. 
 */
SEXP
getDObj(SEXP fname)
{
    SEXP            res;
    DOBJ           *data = NULL;
    long            numRecs;
    /*
     * read the data
     */
    data =
        asspFOpen(strdup(CHAR(STRING_ELT(fname, 0))), AFO_READ,
                  (DOBJ *) NULL);
    if (data == NULL)
        error(getAsspMsg(asspMsgNum));
    /*
     * error(CHAR(STRING_ELT(fname,0)));
     */
    allocDataBuf(data, data->numRecords);
    data->bufStartRec = data->startRecord;
    if ((numRecs = asspFFill(data)) < 0)
        error(getAsspMsg(asspMsgNum));
    asspFClose(data, AFC_KEEP);
    res = PROTECT(dobj2AsspDataObj(data));
    asspFClose(data, AFC_FREE);
    UNPROTECT(1);
    return res;
}
Esempio n. 2
0
/*
 * Originally, we retained the DOBJ and stored a pointer to it in the
 * SEXP. For that reason, garbage collection was an issue and this
 * function was used to clean up the data object when the SEXP was
 * deleted. No longer needed, should be save to remove. 
 */
static void
DObjFinalizer(SEXP dPtr)
{
    DOBJ           *data = R_ExternalPtrAddr(dPtr);
    asspFClose(data, AFC_FREE);
    R_ClearExternalPtr(dPtr);   /* not really needed */
}
Esempio n. 3
0
/*
 * This function performs an analysis routine. The intput to this function 
 * is an SEXP object containing a list of input files, the name of the
 * function and the analysis options. 
 */
SEXP
performAssp(SEXP args)
{
    SEXP            el,
                    inputs,
                    res,
                    pBar = R_NilValue,
        utilsPackage,           /* to update the prograssbar */
        newVal;
    const char     *name;
    AOPTS           OPTS;
    AOPTS          *opt = &OPTS;
    W_OPT          *wrasspOptions;
    A_F_LIST       *anaFunc = funclist;
    int             tmp,
                    expExt = 0,
        toFile = 1,
        i = 0;
    char            ext[SUFF_MAX + 1] = "",
        *cPtr = NULL;
    W_GENDER       *gend = NULL;
    WFLIST         *wPtr = NULL;
    LP_TYPE        *lPtr = NULL;
    SPECT_TYPE     *sPtr = NULL;
    DOBJ           *inPtr,
                   *outPtr;
    char           *dPath,
                   *bPath,
                   *oExt,
                    outName[PATH_MAX + 1],
                   *outDir = NULL;

    args = CDR(args);           /* skip function name */

    /*
     * First element is input file name or vector of input file names 
     */
    inputs = CAR(args);
    args = CDR(args);

    /*
     * Second element must be assp function name
     * check for validity and pick the right function descriptor 
     */
    name = isNull(TAG(args)) ? "" : CHAR(PRINTNAME(TAG(args)));
    if (strcmp(name, "fname") != 0)
        error("Second argument must be named 'fname'");

    el = CAR(args);
    while (anaFunc->funcNum != AF_NONE) {
        if (strcmp(CHAR(STRING_ELT(el, 0)), anaFunc->fName) == 0)
            break;
        anaFunc++;
    }
    if (anaFunc->funcNum == AF_NONE)
        error("Invalid analysis function in performAssp.c");

    /*
     * generate the default settings for the analysis function
     */
    if ((anaFunc->setFunc) (opt) == -1)
        error("%d\t$%s\n", asspMsgNum, getAsspMsg(asspMsgNum));

    args = CDR(args);
    /*
     * the rest is options; each of them is checked against the option list of the analysis function
     */


    for (int i = 0; args != R_NilValue; i++, args = CDR(args)) {
        name = isNull(TAG(args)) ? "" : CHAR(PRINTNAME(TAG(args)));
        wrasspOptions = anaFunc->options;
        while (wrasspOptions->name != NULL) {
            if (strcmp(wrasspOptions->name, name) == 0)
                break;
            wrasspOptions++;
        }
        if (wrasspOptions->name == NULL)
            error("Invalid option %s for ASSP analysis %s.", name,
                  anaFunc->fName);

        el = CAR(args);
        switch (wrasspOptions->optNum) {
        case WO_BEGINTIME:
            opt->beginTime = REAL(el)[0];
            break;
        case WO_ENDTIME:
            opt->endTime = REAL(el)[0];
            break;
        case WO_CENTRETIME:
            if (INTEGER(el)[0]) {
                opt->options |= AOPT_USE_CTIME;
            } else {
                opt->options &= ~AOPT_USE_CTIME;
            }
            break;

        case WO_MSEFFLEN:
            if (INTEGER(el)[0]) {
                opt->options |= AOPT_EFFECTIVE;
                switch (anaFunc->funcNum) {
                case AF_SPECTRUM:
                    opt->options &= ~AOPT_USE_ENBW;
                    break;
                default:
                    /*
                     * do nothing
                     */
                    break;
                }
            } else {
                opt->options &= ~AOPT_EFFECTIVE;
                switch (anaFunc->funcNum) {
                case AF_FOREST:
                    opt->gender = 'u';
                    break;
                default:
                    break;
                }
            }
            break;
        case WO_MSSIZE:
            opt->msSize = REAL(el)[0];
            switch (anaFunc->funcNum) {
            case AF_FOREST:
                switch (opt->gender) {
                case 'f':
                    if (opt->msSize != FMT_DEF_EFFLENf)
                        opt->gender = 'u';
                    break;
                case 'm':
                    if (opt->msSize != FMT_DEF_EFFLENm)
                        opt->gender = 'u';
                    break;
                default:
                    break;
                }
                break;
            case AF_SPECTRUM:
                opt->options &= ~AOPT_USE_ENBW;
                break;
            default:
                /*
                 * do nothing
                 */
                break;
            }
            break;
        case WO_MSSHIFT:
            opt->msShift = REAL(el)[0];
            break;
        case WO_MSSMOOTH:
            opt->msSmooth = REAL(el)[0];
            break;
        case WO_BANDWIDTH:
            opt->bandwidth = REAL(el)[0];
            break;
        case WO_RESOLUTION:
            opt->resolution = REAL(el)[0];
            break;
        case WO_GAIN:
            opt->gain = REAL(el)[0];
            break;
        case WO_RANGE:
            opt->range = REAL(el)[0];
            break;
        case WO_PREEMPH:
            opt->preEmph = REAL(el)[0];
            break;
        case WO_FFTLEN:
            opt->FFTLen = INTEGER(el)[0];
            break;
        case WO_CHANNEL:
            opt->channel = INTEGER(el)[0];
            break;
        case WO_GENDER:
            /*
             * some things need to be set here:
             * for f0_ksv: maxf, minf
             * for f0_mhs: maxf, minf
             * for forest: eff. window length, nominal F1
             */
            gend = gender;
            while (gend->ident != NULL) {
                if (strncmp(gend->ident, CHAR(STRING_ELT(el, 0)), 1) == 0)
                    break;
                gend++;
            }
            if (gend->ident == NULL)
                error("Invalid gender specification %s.",
                      CHAR(STRING_ELT(el, 0)));

            switch (anaFunc->funcNum) {
            case AF_KSV_PITCH:
                tmp = setKSVgenderDefaults(opt, gend->code);
                break;
            case AF_MHS_PITCH:
                tmp = setMHSgenderDefaults(opt, gend->code);
                break;
            case AF_FOREST:
                if (gend->num == TG_UNKNOWN) {
                    opt->gender = tolower((int) gend->code);
                    tmp = 1;
                } else
                    tmp = setFMTgenderDefaults(opt, gend->code);
                break;
            default:
                tmp = 1;
                break;
            }
            if (tmp < 0)
                error("%s", applMessage);
            break;
        case WO_MHS_OPT_POWER:
            if (INTEGER(el)[0])
                opt->options |= MHS_OPT_POWER;
            else
                opt->options &= ~MHS_OPT_POWER;
            break;
        case WO_ORDER:
            tmp = opt->order;
            opt->order = INTEGER(el)[0];
            if (anaFunc->funcNum == AF_FOREST) {
                if ((opt->order % 2) != 0) {
                    opt->order = tmp;
                    error("Prediction order must be an even number.");
                } else {
                    opt->options |= FMT_OPT_LPO_FIXED;
                    opt->increment = 0;
                }
            }
            break;
        case WO_INCREMENT:
            opt->increment = INTEGER(el)[0];
            if (anaFunc->funcNum == AF_FOREST) {
                opt->options &= ~FMT_OPT_LPO_FIXED;
                opt->order = 0;
            }
            break;
        case WO_NUMLEVELS:
            opt->numLevels = INTEGER(el)[0];
            break;
        case WO_NUMFORMANTS:
            opt->numFormants = INTEGER(el)[0];
            break;
        case WO_PRECISION:
            opt->precision = INTEGER(el)[0];
            break;
        case WO_ACCURACY:
            opt->accuracy = INTEGER(el)[0];
            break;
        case WO_ALPHA:
            opt->alpha = REAL(el)[0];
            break;
        case WO_THRESHOLD:
            opt->threshold = REAL(el)[0];
            break;
        case WO_MAXF:
            opt->maxF = REAL(el)[0];
            switch (anaFunc->funcNum) {
            case AF_KSV_PITCH:
            case AF_MHS_PITCH:
                opt->gender = 'u';
                break;
            default:
                /*
                 * do nothing
                 */
                break;
            }
            break;
        case WO_MINF:
            opt->minF = REAL(el)[0];
            switch (anaFunc->funcNum) {
            case AF_KSV_PITCH:
            case AF_MHS_PITCH:
                opt->gender = 'u';
                break;
            default:
                /*
                 * do nothing
                 */
                break;
            }
            break;
        case WO_NOMF1:         /* e.g. for formant analysis */
            opt->nomF1 = REAL(el)[0];
            switch (anaFunc->funcNum) {
            case AF_FOREST:
                switch (opt->gender) {
                case 'f':
                    if (opt->nomF1 != FMT_DEF_NOMF1f)
                        opt->gender = 'u';
                    break;
                case 'm':
                    if (opt->nomF1 != FMT_DEF_NOMF1m)
                        opt->gender = 'u';
                    break;
                default:
                    break;
                }
                break;
            default:
                /*
                 * do nothing
                 */
                break;
            }
            break;
        case WO_INS_EST:
            if (INTEGER(el)[0])
                opt->options |= FMT_OPT_INS_ESTS;
            else
                opt->options &= ~FMT_OPT_INS_ESTS;
            break;
        case WO_VOIAC1PP:      /* VOICING thresholds */
            opt->voiAC1 = REAL(el)[0];
            break;
        case WO_VOIMAG:
            opt->voiMag = REAL(el)[0];
            break;
        case WO_VOIPROB:
            opt->voiProb = REAL(el)[0];
            break;
        case WO_VOIRMS:
            opt->voiRMS = REAL(el)[0];
            break;
        case WO_VOIZCR:
            opt->voiZCR = REAL(el)[0];
            break;
        case WO_HPCUTOFF:      /* filter parameters */
            opt->hpCutOff = REAL(el)[0];
            if (expExt == 0)
                tmp = getFILTtype(opt, anaFunc->defExt);
            break;
        case WO_LPCUTOFF:
            opt->lpCutOff = REAL(el)[0];
            if (expExt == 0)
                tmp = getFILTtype(opt, anaFunc->defExt);
            break;
        case WO_STOPDB:
            opt->stopDB = REAL(el)[0];
            if (expExt == 0)
                tmp = getFILTtype(opt, anaFunc->defExt);
            break;
        case WO_TBWIDTH:
            opt->tbWidth = REAL(el)[0];
            if (expExt == 0)
                tmp = getFILTtype(opt, anaFunc->defExt);
            break;
        case WO_USEIIR:
            if (INTEGER(el)[0])
                opt->options |= FILT_OPT_USE_IIR;
            else
                opt->options &= ~FILT_OPT_USE_IIR;
            if (expExt == 0)
                tmp = getFILTtype(opt, anaFunc->defExt);
            break;
        case WO_NUMIIRSECS:
            opt->order = INTEGER(el)[0];
            if (opt->order < 1) {
                error
                    ("Bad value for option -numIIRsections (%i), must be greater 0 (default 4).",
                     opt->order);
                opt->order = FILT_DEF_SECTS;
            }
            break;
        case WO_TYPE:          /* hold-all */
            switch (anaFunc->funcNum) {
            case AF_RFCANA:
                lPtr = lpType;
                while (lPtr->ident != NULL) {
                    if (strcmp(lPtr->ident, CHAR(STRING_ELT(el, 0))) == 0)
                        break;
                    lPtr++;
                }
                if (lPtr->ident == NULL)
                    error("Invalid LP Type: %s.", CHAR(STRING_ELT(el, 0)));
                strncpy(opt->type, lPtr->ident, strlen(lPtr->ident));
                if (expExt == 0)
                    strncpy(ext, lPtr->ext, strlen(lPtr->ext));
                break;
            case AF_SPECTRUM:
                sPtr = spectType;
                while (sPtr->ident != NULL) {
                    if (strcmp(sPtr->ident, CHAR(STRING_ELT(el, 0))) == 0)
                        break;
                    sPtr++;
                }
                if (sPtr->ident == NULL)
                    error("Invalid SP Type: %s.", CHAR(STRING_ELT(el, 0)));
                strncpy(opt->type, sPtr->ident, strlen(sPtr->ident));
                if (setSPECTdefaults(opt) < 0) {
                    error("%s", getAsspMsg(asspMsgNum));
                }
                strncpy(opt->type, sPtr->ident, strlen(sPtr->ident));
                switch (sPtr->type) {
                case DT_FTPOW:
                case DT_FTAMP:
                case DT_FTSQR:
                    setDFTdefaults(opt);
                    break;
                case DT_FTLPS:
                    setLPSdefaults(opt);
                    break;
                case DT_FTCSS:
                    setCSSdefaults(opt);
                    break;
                case DT_FTCEP:
                    setCEPdefaults(opt);
                    break;
                default:
                    setAsspMsg(AEG_ERR_BUG,
                               "setSPECTdefaults: invalid default type");
                    error("%s.", getAsspMsg(asspMsgNum));
                    break;
                }
                if (expExt == 0)
                    strncpy(ext, sPtr->ext, strlen(sPtr->ext));
                break;
            default:
                break;
            }
            break;
        case WO_WINFUNC:
            wPtr = wfShortList;
            while (wPtr->code != NULL) {
                if (strcmp(wPtr->code, CHAR(STRING_ELT(el, 0))) == 0)
                    break;
                wPtr++;
            }
            if (wPtr->code == NULL)
                error("Invalid window function code %s.",
                      CHAR(STRING_ELT(el, 0)));
            strncpy(opt->winFunc, wPtr->code, strlen(wPtr->code));
            break;
            /*
             * These are not in libassp but in wrassp
             */
        case WO_ENERGYNORM:
            if (INTEGER(el)[0])
                opt->options |= ACF_OPT_NORM;
            else
                opt->options &= ~ACF_OPT_NORM;
            break;
        case WO_LENGTHNORM:
            if (INTEGER(el)[0])
                opt->options |= ACF_OPT_MEAN;
            else
                opt->options &= ~ACF_OPT_MEAN;
            break;
        case WO_DIFF_OPT_BACKWARD:
            if (INTEGER(el)[0])
                opt->options |= DIFF_OPT_BACKWARD;
            else
                opt->options &= ~DIFF_OPT_BACKWARD;
            break;
        case WO_DIFF_OPT_CENTRAL:
            if (INTEGER(el)[0])
                opt->options |= DIFF_OPT_CENTRAL;
            else
                opt->options &= ~DIFF_OPT_CENTRAL;
            break;
        case WO_RMS_OPT_LINEAR:
            if (INTEGER(el)[0])
                opt->options |= RMS_OPT_LINEAR;
            else
                opt->options &= ~RMS_OPT_LINEAR;
            break;
        case WO_LPS_OPT_DEEMPH:
            if (INTEGER(el)[0])
                opt->options |= LPS_OPT_DEEMPH;
            else
                opt->options &= ~LPS_OPT_DEEMPH;
            break;
        case WO_OUTPUTEXT:
            if (TYPEOF(el) == NILSXP) {
                expExt = 0;
                break;
            }
            cPtr = strdup(CHAR(STRING_ELT(el, 0)));
            if (*cPtr != '.' && strlen(cPtr) != 0) {
                strncpy(ext, ".", strlen(".") + 1);
                strcat(ext, cPtr);
            } else {
                strncpy(ext, cPtr, strlen(cPtr) + 1);
            }
            free(cPtr);
            expExt = 1;
            switch (anaFunc->funcNum) {
            case AF_RFCANA:
                lPtr = lpType;
                while (lPtr->ident != NULL) {
                    if (strcmp(opt->type, lPtr->ident) == 0)
                        break;
                    lPtr++;
                }
                if (lPtr->ident == NULL)
                    error("Bad LP Type in memory (%s).", opt->type);
                if (strcmp(lPtr->ext, ext) == 0) {
                    expExt = 0;
                } else {
                    expExt = 1;
                }
                break;
            case AF_SPECTRUM:
                sPtr = spectType;
                while (sPtr->ident != NULL) {
                    if (strcmp(opt->type, sPtr->ident) == 0)
                        break;
                    sPtr++;
                }
                if (sPtr->ident == NULL)
                    error("Bad SP Type in memory (%s).", opt->type);
                if (strcmp(sPtr->ext, ext) == 0) {
                    expExt = 0;
                } else {
                    expExt = 1;

                }
                break;
            default:
                break;
            }
            break;
        case WO_TOFILE:
            toFile = INTEGER(el)[0] != 0;
            break;
        case WO_OUTPUTDIR:
            if (el == R_NilValue) {
                outDir = NULL;
                break;
            }
            outDir = strdup(CHAR(STRING_ELT(el, 0)));
            if (outDir[strlen(outDir) - 1] != DIR_SEP_CHR) {
                /* add trailing slash, but we need a bit more space first */
                char *tmp = malloc(strlen(outDir) + 2);
                strcpy(tmp, outDir);
                tmp = strcat(tmp, DIR_SEP_STR);
                free(outDir);
                outDir = tmp;
            }
            break;
        case WO_PBAR:
            pBar = el;
            break;
        default:
            break;
        }
    }

    /*
     * output extension might still be unset. For afdiff and for spectral 
     * analysis we need to take special care. In other cases it would be
     * weird to get here but we can safely use the default. 
     */
    if (strcmp(ext, "") == 0) {
        /*
         * could be explicitely set to ""
         */
        if (!expExt) {
            switch (anaFunc->funcNum) {
            case AF_AFDIFF:
                /*
                 * needs to be handled on a per file basis
                 */
                break;
            case AF_SPECTRUM:
                sPtr = spectType;
                while (sPtr->ident != NULL) {
                    if (strcmp(opt->type, sPtr->ident) == 0)
                        break;
                    sPtr++;
                }
                if (sPtr->ident == NULL)
                    error("Bad SP Type in memory (%s).", opt->type);
                strcpy(ext, sPtr->ext);
                break;
            default:
                strcpy(ext, anaFunc->defExt);
                break;
            }
        }
    }
    /*
     * do analysis
     */

    /*
     * hook into the progressbar if present 
     */
    if (pBar != R_NilValue) {
        PROTECT(newVal = allocVector(INTSXP, 1));
        PROTECT(utilsPackage = eval(lang2(install("getNamespace"),
                                          ScalarString(mkChar("utils"))),
                                    R_GlobalEnv));
        INTEGER(newVal)[0] = 0;
        eval(lang4(install("setTxtProgressBar"), pBar, newVal, R_NilValue),
             utilsPackage);
    }

    /*
     * in memory only works for single input, not for multiple input so,
     * if toFile is false but there are multiple inputs set toFile to true 
     */
    toFile = toFile || length(inputs) != 1;

    /*
     * iterate over input files 
     */
    for (i = 0; i < length(inputs); i++) {
        /*
         * get inpput name and open
         */
        name = strdup(CHAR(STRING_ELT(inputs, i)));
        inPtr = asspFOpen(strdup(name), AFO_READ, (DOBJ *) NULL);
        if (inPtr == NULL)
            error("%s (%s)", getAsspMsg(asspMsgNum), strdup(name));

        /*
         * run the function (as pointed to in the descriptor) to generate
         * the output object 
         */
        outPtr = (anaFunc->compProc) (inPtr, opt, (DOBJ *) NULL);
        if (outPtr == NULL) {
            asspFClose(inPtr, AFC_FREE);
            error("%s (%s)", getAsspMsg(asspMsgNum), strdup(name));
        }

        /*
         * input data object no longer needed 
         */
        asspFClose(inPtr, AFC_FREE);


        if (toFile) {
            /*
             * in toFile mode, all DOBJs are written to file we will later 
             * return the number of successful analyses 
             */

            /*
             * parse the input path to get directory (dPath), base file
             * name (bPath) and original extension (oExt) 
             */
            parsepath((char *) name, &dPath, &bPath, &oExt);
            /*
             * outName is the same except for extension unless outDir is
             * set 
             */
            strcpy(outName, "");
            if (outDir == NULL)
                strcat(outName, dPath);
            else
                strcat(outName, outDir);
            strcat(outName, bPath);
            /*
             * Extension may have to be set for afdiff but only if
             * extension is not set explicitely 
             */
            if (strcmp(ext, "") == 0 && !expExt) {
                switch (anaFunc->funcNum) {
                case AF_AFDIFF:
                    strcpy(ext, ".d");
                    oExt++;     /* skip period */
                    strcat(ext, oExt);
                    break;
                default:
                    error("Extension handling failed (performAssp).");
                    break;
                }
            }
            strcat(outName, ext);

            /*
             * out put name is complete, use it to open the file for the
             * output object, then write and close and free 
             */
            outPtr = asspFOpen(outName, AFO_WRITE, outPtr);
            if (outPtr == NULL) {
                asspFClose(outPtr, AFC_FREE);
                error("%s (%s)", getAsspMsg(asspMsgNum), strdup(outName));
            }
            if (asspFFlush(outPtr, 0) == -1) {
                asspFClose(outPtr, AFC_FREE);
                error("%s (%s)", getAsspMsg(asspMsgNum), strdup(outName));
            }
            asspFClose(outPtr, AFC_FREE);
        } else {
            res = dobj2AsspDataObj(outPtr);
            asspFClose(outPtr, AFC_FREE);
        }

        free((char *) name);

        /*
         * if a progress bar was passed over, increment its value
         */
        if (pBar != R_NilValue) {
            INTEGER(newVal)[0] = i + 1;
            eval(lang4
                 (install("setTxtProgressBar"), pBar, newVal, R_NilValue),
                 utilsPackage);
        }
    }
    free((void *) outDir);
    if (toFile) {
        /*
         * in toFile mode, the number of successful analyses is returned
         */
        PROTECT(res = allocVector(INTSXP, 1));
        INTEGER(res)[0] = i;
    }
    /*
     * for the progress bar, to SEXPs were protected
     */
    if (pBar != R_NilValue)
        UNPROTECT(2);

    /*
     * in toFile mode, the return value was protected
     */
    if (toFile)
        UNPROTECT(1);
    return res;
}
Esempio n. 4
0
/*
 * This function loads a DOBJ from a file and return its contents as a
 * SEXP. Arguments include the name of the input file, start and end point 
 * for reading and whether these points are sample values (and not times) 
 */
SEXP
getDObj2(SEXP args)
{

    SEXP            el,
                    ans;
    DOBJ           *data = NULL;
    long            numRecs;
    int             i;
    char           *fName = NULL;
    const char     *name;
    double          begin = 0,
        end = 0;
    int             isSample = 0;

    /*
     * parse args
     */
    args = CDR(args);           /* skip name of function */
    el = CAR(args);
    fName = strdup(CHAR(STRING_ELT(el, 0)));

    args = CDR(args);
    for (i = 0; args != R_NilValue; i++, args = CDR(args)) {
        name = isNull(TAG(args)) ? "" : CHAR(PRINTNAME(TAG(args)));
        el = CAR(args);
        if (strcmp(name, "begin") == 0) {
            begin = REAL(el)[0];
            if (begin < 0)
                begin = 0;
        } else if (strcmp(name, "end") == 0) {
            end = REAL(el)[0];
            if (end < 0)
                end = 0;
        } else if (strcmp(name, "samples") == 0) {
            isSample = INTEGER(el)[0];
        } else {
            error("Bad option '%s'.", name);
        }
    }

    if (end < begin && end > 0)
        error("End before begin. That's not clever, dude!");

    /*
     * open the file
     */
    data = asspFOpen(fName, AFO_READ, (DOBJ *) NULL);
    if (data == NULL)
        error("%s (%s)", getAsspMsg(asspMsgNum), fName);
    /*
     * figure out timing
     */
    if (isSample) {
        if (end == 0)
            end = data->startRecord + data->numRecords - 1;
    } else {
        begin = ceil(begin * data->dataRate) + data->startRecord;
        if (end == 0)
            end = data->startRecord + data->numRecords - 1;
        else
            end = floor(end * data->dataRate) + data->startRecord;
    }
    if (end > (data->startRecord + data->numRecords))
        end = data->startRecord + data->numRecords - 1;
    if (begin > (data->startRecord + data->numRecords)) {
        asspFClose(data, AFC_FREE);
        error("Begin after end of data. That's not clever, dude!");
    }

    numRecs = (long) (end - begin) + 1;
    /*
     * read the data
     */
    allocDataBuf(data, numRecs);
    data->bufStartRec = (long) begin;
    if ((numRecs = asspFFill(data)) < 0) {
        asspFClose(data, AFC_FREE);
        error(getAsspMsg(asspMsgNum));
    }
    asspFClose(data, AFC_KEEP);
    ans = PROTECT(dobj2AsspDataObj(data));
    asspFClose(data, AFC_FREE);
    UNPROTECT(1);
    return ans;
}