resample.c 6.14 KB
/*====================================================================
 * resample.c
 *
 * Copyright 1993, Silicon Graphics, Inc.
 * All Rights Reserved.
 *
 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
 * Inc.; the contents of this file may not be disclosed to third
 * parties, copied or duplicated in any form, in whole or in part,
 * without the prior written permission of Silicon Graphics, Inc.
 *
 * RESTRICTED RIGHTS LEGEND:
 * Use, duplication or disclosure by the Government is subject to
 * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
 * in Technical Data and Computer Software clause at DFARS
 * 252.227-7013, and/or in similar or successor clauses in the FAR,
 * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
 * Copyright Laws of the United States.
 *====================================================================*/

#include <libaudio.h>
#include "synthInternals.h"
#include <em.h>
#include <os.h>
#include <stdio.h>

/*
 * prototypes for private resampler functions
 */
static  Acmd *_pullSubFrame(void *filter, short *inp, short *outp,
                            int outCount, int flags, Acmd *p) ;

/***********************************************************************
 * Resampler filter public interfaces
 ***********************************************************************/
void alResampleNew(ALResampler *r)
{
    alFilterNew((ALFilter *) r, alResamplePull, alResampleParam, AL_RESAMPLE);

    /*
     * Init resampler state
     */
    r->delta  = 0.0;
    r->first  = 1;
    r->motion = AL_STOPPED;
    
    /* state in the ucode is initialized by the A_INIT flag */

}

Acmd *alResamplePull(void *filter, short *outp, int outCnt, int flags, Acmd *p) 
{
    ALResampler *f = (ALResampler *)filter;
    Acmd        *ptr = p;
    short       inp;
    int         inCount;
    int         lastOffset;
    int         thisOffset = 0;
    int         samples;
    short       loutp = *outp;
    
    inp = AL_DECODER_OUT;
    
    f->ctrlTail = 0; 
    for ( ;f->ctrlList != 0; f->ctrlList = f->ctrlList->next) {

        lastOffset = thisOffset;
        thisOffset = f->ctrlList->delta;
        samples    = thisOffset - lastOffset;
        
        switch (f->ctrlList->type) {
            case (AL_FILTER_SET_STATE):
                if (f->ctrlList->data.i == AL_PLAYING) {                    
                    (*f->filter.setParam)(&f->filter, AL_FILTER_START, 0);
                } else {
                    ptr = _pullSubFrame(f, &inp, &loutp, samples, flags, ptr);
                    (*f->filter.setParam)(&f->filter, AL_FILTER_RESET, 0);
                }
                break;

            default:
                ptr = _pullSubFrame(f, &inp, &loutp, samples, flags, ptr);
                (*f->filter.setParam)(&f->filter, f->ctrlList->type,                                       (void *) f->ctrlList->data.i);
                break;
        }
        loutp  += (samples<<1);
        outCnt -= samples;
    }
    
    if (f->motion == AL_PLAYING) 
        ptr = _pullSubFrame(f, &inp, &loutp, outCnt, flags, ptr);
    
    return ptr;
}

int alResampleParam(void *filter, int paramID, void *param)
{
    ALFilter      *f = (ALFilter *) filter;
    ALResampler   *r = (ALResampler *) filter;
    union {
        float           f;
        int             i;
    } data;
    
    switch (paramID) {

        case (AL_FILTER_SET_SOURCE):
            f->source = (ALFilter *) param;
            break;
	  
        case (AL_FILTER_ADD_UPDATE):
            if (r->ctrlTail) {
                r->ctrlTail->next = (ALParam *)param;
            } else {
                r->ctrlList = (ALParam *)param;
            }            
            r->ctrlTail = (ALParam *)param;
            break;
        
        case (AL_FILTER_RESET):
            r->delta  = 0.0;
            r->first  = 1;
            r->motion = AL_STOPPED;
            if (f->source)
                (*f->source->setParam)(f->source, AL_FILTER_RESET, 0);
            break;

        case (AL_FILTER_START):
            r->motion = AL_PLAYING;
            if (f->source)
                (*f->source->setParam)(f->source, AL_FILTER_START, 0);
            break;
            
        case (AL_FILTER_SET_PITCH):
            data.i = (int) param;
            r->ratio = data.f;
            break;
            
	case (AL_FILTER_SET_UNITY_PITCH):
	    r->upitch = 1;
            break;
            
        default:
            if (f->source)
                (*f->source->setParam)(f->source, paramID, param);
            break;
    }
    return 0;
}

Acmd *_pullSubFrame(void *filter, short *inp, short *outp, int outCount,
                    int flags, Acmd *p) 
{
    Acmd        *ptr = p;
    int         inCount;
    ALResampler   *f = (ALResampler *)filter;
    ALFilter      *source;
    int		incr;
    float       finCount;
    
    if (!outCount)
        return ptr;

    /*
     * check if resampler is required
     */
    if (f->upitch) {

	if (source = f->filter.source) {
	    ptr = (*source->handler)(source, inp, outCount, flags, p);
	} else {
	    /* error */
	}
	aDMEMMove(ptr++, *inp, *outp, outCount<<1);

    } else {

	/*
	 * clip to maximum allowable pitch
	 * FIXME: should we check for some minimum as well?
	 */
	if (f->ratio > MAX_RATIO) f->ratio = MAX_RATIO;

	/*
	 * quantize the pitch
	 */
	f->ratio = (int)(f->ratio * UNITY_PITCH);
	f->ratio = f->ratio / UNITY_PITCH;

	/*
	 * determine how many samples to generate
	 */
	finCount = f->delta + (f->ratio * (float) outCount);
	inCount = (int) finCount;
	f->delta = finCount - (float)inCount;

	/*
	 * ask all filters upstream from us to build their command
	 * lists.
	 */
	if (source = f->filter.source) {
	    ptr = (*source->handler)(source, inp, inCount, flags, p);
	} else {
	    /* error */
	}

	/*
	 * construct our portion of the command list
	 */
	incr = (int)(f->ratio * UNITY_PITCH);
	aSetBuffer(ptr++, 0, *inp, *outp, outCount<<1);
	if (f->first){
	    f->first = 0;
	    aResample(ptr++, A_INIT, incr, osVirtualToPhysical(f->state.rstate));
	}
	else
	    aResample(ptr++, 0, incr, osVirtualToPhysical(f->state.rstate));
    }

    /*
     * bump the input buffer pointer
     */
    *inp += (inCount<<1);
    
    return ptr;
}