Logo Search packages:      
Sourcecode: csound version File versions  Download package

pluck.c

/*  
    pluck.c:

    Copyright (C) 1994, 2000 Michael A. Casey, John ffitch

    This file is part of Csound.

    The Csound Library is free software; you can redistribute it
    and/or modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    Csound is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with Csound; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
    02111-1307 USA
*/


/* pluck.c -- plucked string class definitions */

/*
 * Code conversion from C++ to C (October 1994)
 * Author: Michael A. Casey MIT Media Labs
 * Language: C
 * Copyright (c) 1994 MIT Media Lab, All Rights Reserved
 * Some modifications John ffitch, 2000, simplifying code
 */

#include "cs.h"
#include "wavegde.h"
#include "pluck.h"

#ifdef BETA
#define WG_VERBOSE BETA
#endif

/* external prototypes */
extern void error(const char*, const char*);

/* ***** plucked string class member function definitions ***** */

/* pluck::excite -- excitation function for plucked string */
void pluckExcite(WGPLUCK* p)
{
    MYFLT *shape;
    int i;
    int size = p->wg.upperRail.size;

    /* set the delay element to pick at */
    p->pickSamp=(len_t)(size * *p->pickPos);
    if (p->pickSamp<1)
      p->pickSamp = 1;

    /* set the bridge filter coefficients for the correct magnitude response */
    pluckSetFilters(p,*p->Aw0,*p->AwPI);/*attenuation in dB at w0 and PI*/

    /* add the pick shape to the waveguide rails */
    shape = pluckShape(p);    /* Efficiency loss here */

    /* add shape to lower rail */
    for (i=0;i<size;i++) {
      p->wg.lowerRail.data[i] = shape[i]; /* Why add? Starts at zero anyway */
      p->wg.upperRail.data[size-i-1] = shape[i];
    }
    /* free the space used by the pluck shape */
    mfree((char*)shape);

    /* Reset the tuning and bridge filters */
}

/* ::pluck -- create the plucked-string instrument */
void pluckPluck(WGPLUCK* p)
{

    /* ndelay = total required delay - 1.0 */
    len_t ndelay = (len_t) (esr / *p->freq - FL(1.0));

#ifdef WG_VERBOSE
    printf("pluckPluck -- allocating memory ndelay=%d...", ndelay);
#endif

    /* Allocate auxillary memory or reallocate if size has changed */
    auxalloc((len_t)(ndelay/2)*sizeof(MYFLT), &p->upperData);
    auxalloc((len_t)(ndelay/2)*sizeof(MYFLT), &p->lowerData);

#ifdef WG_VERBOSE
    printf("done.\n");
#endif

    /* construct waveguide object */
#ifdef WG_VERBOSE
    printf("Constructing waveguide...");
#endif

    waveguideWaveguide((waveguide*)&p->wg,             /* waveguide       */
                       (MYFLT)*p->freq,                /* f0 frequency    */
                       (MYFLT*)p->upperData.auxp,      /* upper rail data */
                       (MYFLT*)p->lowerData.auxp);     /* lower rail data */
#ifdef WG_VERBOSE
    printf("done.\n");
#endif
    /* Excite the string with the input parameters */
#ifdef WG_VERBOSE
    printf("Exciting the string...");
#endif
    pluckExcite(p);
#ifdef WG_VERBOSE
    printf("done\n");
    {
      int i;
      for (i=0;i<p->wg.lowerRail.size;i++) {
        printf("%d: %f, %f%c", i, p->wg.lowerRail.data[i], p->wg.upperRail.data[i], (i%4==3?'\n':'\t'));
      }
      printf("\n");
    }
#endif
}

/* pluck::setFilters -- frequency dependent filter calculations */
void pluckSetFilters(WGPLUCK* p, MYFLT A_w0, MYFLT A_PI)
{
    /* Define the required magnitude response of H1 at w0 and PI */

    /* Constrain attenuation specification to dB per second */
    double NRecip = (double)(p->wg.f0/esr); /*  N=t*esr/f0  */
    MYFLT H1_w0 = (MYFLT) pow(10.0,-(double)A_w0*0.05*NRecip);
    MYFLT H1_PI = (MYFLT) pow(10.0,-(double)A_PI*0.05*NRecip);
/*      printf("Aw0 = %f Api = %f (%f, %f)\n", A_w0, A_PI, H1_w0,H1_PI ); */
    {
      /* The tuning filter is allpass, so no dependency for H1 */
      /* therefore solve for the coefficients of the bridge filter directly */
      MYFLT cosw0 = (MYFLT)cos((double)p->wg.w0);
      MYFLT a1=(H1_w0+cosw0*H1_PI)/(1+cosw0);
      MYFLT a0 = (a1 - H1_PI)*FL(0.5);
      /*      printf("cosw0 = %f\n", cosw0); */
      /* apply constraints on coefficients (see Sullivan)*/
      if ((a0<FL(0.0))|| (a1<a0+a0)) {
        a0=FL(0.0);
        a1=H1_w0;
      }
      
      filter3Set(&p->bridge,a0, a1);   /* set the new bridge coefficients */
      
      /*  if (VERBOSE)
          printf("bridge :a0=%f, a1=%f\n",a0,a1);
      */
    }
}

/* ::pluckShape -- the pluck function for a string */
MYFLT *pluckShape(WGPLUCK* p)
{
    MYFLT scale = *p->amp;
    MYFLT  *shape;
    len_t len=p->wg.lowerRail.size;
    len_t i;
    MYFLT M;

    /* This memory must be freed after use */
    shape = (MYFLT *) mmalloc(len*sizeof(MYFLT));
    if (!shape)
      error(Str(X_231,"Couldn't allocate for initial shape"),"<pluckShape>");

    scale = FL(0.5) * scale;      /* Scale was squared!! */
    for (i=0;i<p->pickSamp;i++)
      shape[i] = scale*i / p->pickSamp;

    M = (MYFLT)len - p->pickSamp;
    for (i=0;i<M;i++)
      shape[p->pickSamp+i] = scale - (i*scale/M);

    return shape;
}


/* ::getSamps -- the sample generating routine */
void pluckGetSamps(WGPLUCK* p)
{
    MYFLT       yr0,yl0,yrM,ylM;        /* Key positions on the waveguide */
    MYFLT *ar = p->out;    /* The sample output buffer */
    len_t M=p->wg.upperRail.size; /* Length of the guide rail */
    len_t N=ksmps;
/*    int i = 0; */
    MYFLT *fdbk = p->afdbk;
    /* set the delay element to pickup at */
    len_t pickupSamp=(len_t)(M * *p->pickupPos);
    if (pickupSamp<1) pickupSamp = 1;

    /* calculate N samples of the plucked string algorithm */
      do {
/*          void dumpRail(guideRail*, len_t); */
/*          dumpRail(&p->wg.upperRail, M-1); */
/*          dumpRail(&p->wg.lowerRail, M-1); */
        *ar++ = guideRailAccess(&p->wg.upperRail,pickupSamp)
               +guideRailAccess(&p->wg.lowerRail,M-pickupSamp);
        /*        sampBuf[i++] += *fdbk++; */
        yrM = guideRailAccess(&p->wg.upperRail,M-1);/* wave into the nut */
        ylM = -yrM;                 /* reflect the incoming sample at the nut */

        yl0 = guideRailAccess(&p->wg.lowerRail,0);  /* wave into bridge */
#ifdef WG_VERBOSE
        printf("Removing %.2f (upper) and %.2f (lower)\n", yrM, yl0);
#endif
        yr0 = -filter3FIR(&p->bridge,yl0);   /* bridge reflection filter */
        yr0 = filterAllpass(&p->wg,yr0);     /* allpass tuning filter */
        yr0 += *fdbk++;           /* Surely better to inject here */
        guideRailUpdate(&p->wg.upperRail,yr0);    /* update the upper rail*/
        guideRailUpdate(&p->wg.lowerRail,ylM);    /* update the lower rail*/
#ifdef WG_VERBOSE
        printf("inserting %.2f (upper) and %.2f (lower)\n", yr0, ylM);
#endif
      } while(--N);
}


Generated by  Doxygen 1.6.0   Back to index