tomwalters@0: /* tomwalters@0: Copyright (c) Applied Psychology Unit, Medical Research Council. 1988, 1989 tomwalters@0: =========================================================================== tomwalters@0: tomwalters@0: Permission to use, copy, modify, and distribute this software without fee tomwalters@0: is hereby granted for research purposes, provided that this copyright tomwalters@0: notice appears in all copies and in all supporting documentation, and that tomwalters@0: the software is not redistributed for any fee (except for a nominal shipping tomwalters@0: charge). Anyone wanting to incorporate all or part of this software in a tomwalters@0: commercial product must obtain a license from the Medical Research Council. tomwalters@0: tomwalters@0: The MRC makes no representations about the suitability of this tomwalters@0: software for any purpose. It is provided "as is" without express or implied tomwalters@0: warranty. tomwalters@0: tomwalters@0: THE MRC DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING tomwalters@0: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE tomwalters@0: A.P.U. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY tomwalters@0: DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN tomwalters@0: AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF tomwalters@0: OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. tomwalters@0: */ tomwalters@0: tomwalters@0: /* tomwalters@0: Acknowledgment: tomwalters@0: ============== tomwalters@0: tomwalters@0: The source code provided in this file was originally developed by tomwalters@0: Christian Giguere as part of a Ph.D degree at the Department of tomwalters@0: Engineering of the University of Cambridge from April 1990 to tomwalters@0: November 1993. The code was subsequently adapted under a grant tomwalters@0: from the Hearing Research Trust for full compatibility with tomwalters@0: AIM Release 6.15. tomwalters@0: tomwalters@0: Christian Giguere 25/03/94 tomwalters@0: tomwalters@0: */ tomwalters@0: tomwalters@0: /* tomwalters@0: =========================================================== tomwalters@0: upsample.c tomwalters@0: =========================================================== tomwalters@0: tomwalters@0: Upsampling module (FIR filter interpolation method). tomwalters@0: tomwalters@0: Author : Christian Giguere tomwalters@0: First written : 23rd November, 1990 tomwalters@0: Last edited : 09th February, 1994 tomwalters@0: tomwalters@0: Reference: tomwalters@0: (1) L.R.Rabiner and R.W.Schafer (1978). Digital Processing of tomwalters@0: Speech Signals (Prentice-Hall), Section 2.4.2. tomwalters@0: =========================================================== tomwalters@0: */ tomwalters@0: tomwalters@0: /***** includes *****/ tomwalters@0: tomwalters@0: #include tomwalters@0: #include tomwalters@0: #include "stitch.h" tomwalters@0: #include "source.h" tomwalters@0: #include "calc.h" tomwalters@0: #include "calc_tl.h" tomwalters@0: #include "fir.h" tomwalters@0: #include "upsample.h" tomwalters@0: tomwalters@0: tomwalters@0: /***** defines *****/ tomwalters@0: tomwalters@0: #define SEGMENT ( 2048 ) /* number of new points allocated and retained */ tomwalters@0: /* on each call to input source */ tomwalters@0: tomwalters@0: tomwalters@0: /***** functions *****/ tomwalters@0: tomwalters@0: /******************************************************************************* tomwalters@0: * name: function: tomwalters@0: * tomwalters@0: * upsample_callback() Callable procedure returning pointer to upsampled data. tomwalters@0: * tomwalters@0: * UpSample() Setup and initialization function for the design of an tomwalters@0: * FIR interpolation filter. Returns pointer to a new source. tomwalters@0: ********************************************************************************/ tomwalters@0: tomwalters@0: struct _upsample_state { tomwalters@0: struct _fillable_source parent ; tomwalters@0: Source source ; tomwalters@0: Pointer input ; tomwalters@0: int iptr, inout_size ; tomwalters@0: int zerocount, upsample_factor, sample_delay, active ; tomwalters@0: void (*proc)(), (*close)() ; tomwalters@0: FIRfilterState *states ; tomwalters@0: } ; tomwalters@0: tomwalters@0: tomwalters@0: /************************* upsample_callback() ******************************/ tomwalters@0: tomwalters@0: static Pointer upsample_callback( state, bytes, buffer ) tomwalters@0: struct _upsample_state *state ; tomwalters@0: ByteCount *bytes ; tomwalters@0: Pointer buffer ; tomwalters@0: { tomwalters@0: register DataType *optr, *eptr, *pstart ; tomwalters@0: register int last = *bytes == 0 ; tomwalters@0: register int points, bytecount ; tomwalters@0: tomwalters@0: /***** process *****/ tomwalters@0: if( !last ) { tomwalters@0: tomwalters@0: for( bytecount=0 ; bytecount<*bytes ; ) { tomwalters@0: tomwalters@0: /*** get input data ***/ tomwalters@0: points = ( *bytes - bytecount ) / state->inout_size ; tomwalters@0: points = MIN( points, state->upsample_factor * SEGMENT ) ; tomwalters@0: tomwalters@0: if( !state->active ) { tomwalters@0: tomwalters@0: if( state->sample_delay == 0 ) tomwalters@0: state->active = 1 ; tomwalters@0: tomwalters@0: else if( state->sample_delay > points ) tomwalters@0: state->sample_delay -= points ; tomwalters@0: tomwalters@0: else { tomwalters@0: points = state->sample_delay ; tomwalters@0: state->sample_delay = 0 ; tomwalters@0: } tomwalters@0: } tomwalters@0: tomwalters@0: if( state->iptr + ( points - 1 ) / state->upsample_factor >= SEGMENT ) { tomwalters@0: state->input = Pull( state->source, SEGMENT * state->inout_size ) ; tomwalters@0: state->iptr -= SEGMENT ; tomwalters@0: } tomwalters@0: tomwalters@0: /*** fill output buffer with input points interspaced with zeros prior to FIR filtering ***/ tomwalters@0: pstart = ( DataType * ) state->input ; tomwalters@0: optr = ( DataType * ) ( buffer + bytecount ) ; tomwalters@0: eptr = optr + points ; tomwalters@0: tomwalters@0: while( optr < eptr ) { tomwalters@0: tomwalters@0: if( ( state->zerocount %= state->upsample_factor ) > 0 ) tomwalters@0: *optr++ = 0 ; tomwalters@0: tomwalters@0: else tomwalters@0: *optr++ = pstart[state->iptr++] ; tomwalters@0: tomwalters@0: state->zerocount++ ; tomwalters@0: } tomwalters@0: tomwalters@0: /*** filter data ***/ tomwalters@0: state->proc( state->states, buffer+bytecount, points ) ; tomwalters@0: tomwalters@0: /*** loop counts ***/ tomwalters@0: bytecount += points * state->inout_size * state->active ; tomwalters@0: } tomwalters@0: tomwalters@0: return ( buffer ) ; tomwalters@0: } tomwalters@0: tomwalters@0: tomwalters@0: /***** close *****/ tomwalters@0: else { tomwalters@0: Pull( state->source, 0 ) ; tomwalters@0: state->close( state->states ) ; tomwalters@0: tomwalters@0: return ( DeleteFillableSource( state ) ) ; tomwalters@0: } tomwalters@0: tomwalters@0: } tomwalters@0: tomwalters@0: tomwalters@0: /****************************** UpSample() **********************************/ tomwalters@0: tomwalters@0: Source UpSample( source, oldsamplerate, cutoff_freq, upsample_factor ) tomwalters@0: Source source ; tomwalters@0: double oldsamplerate, cutoff_freq ; tomwalters@0: int upsample_factor ; tomwalters@0: { tomwalters@0: DeclareNew( struct _upsample_state *, state ) ; tomwalters@0: double filterGain, wc ; tomwalters@0: tomwalters@0: /***** initialise input-related parameters *****/ tomwalters@0: state->inout_size = sizeof ( DataType ) ; tomwalters@0: state->input = ( Pointer ) 0 ; tomwalters@0: state->iptr = SEGMENT ; tomwalters@0: state->source = NewRetainingSource( source, SEGMENT * state->inout_size ) ; tomwalters@0: state->zerocount = 0 ; tomwalters@0: state->upsample_factor = upsample_factor ; tomwalters@0: tomwalters@0: /***** Specify FIR filter design parameters *****/ tomwalters@0: wc = cutoff_freq / ( state->upsample_factor * oldsamplerate ) * TwoPi ; tomwalters@0: state->states = NewLpFIRfilter( wc, upsample_factor, &state->sample_delay ) ; tomwalters@0: state->active = 0 ; tomwalters@0: state->proc = DoFIRfilter ; tomwalters@0: state->close = CloseFIRfilter ; tomwalters@0: tomwalters@0: /***** return *****/ tomwalters@0: source = SetFillableSource( state, upsample_callback, "upsample buffering" ) ; tomwalters@0: return ( source ) ; tomwalters@0: tomwalters@0: } tomwalters@0: