Digital SVF Code

Mikko Helin MHELIN at tne01.ntc.nokia.com
Tue Mar 9 12:52:13 CET 1999


Hi,

I found the code I promised to send. You can download it
from http://www.uta.fi/~helin/ds2.zip, or in the end of this
message (C source code).

If you want just to listen to it, there a .WAV file (130 kB)
at http://www.uta.fi/~helin/test.wav

Code is optimized for 32-bit processor, the filter needs only
three multiplications. I guess any 386 -> could run it real
time. Maybe some microcontrollers like Siemens 80C188 or
other 16 bit device with 32 bit multiplication accumulator
register.

-Mikko


//////////////// cut here //////////// cut here //////////////

/*
 * DOSYNTH v. 0.2
 *
 * DS2.C
 *
 * This program is based on the algorithm found in Hal Chamberlin's
 * book "Musical Applications of Microprocessors" p. 149-151
 * describing digital implementation of state-variable filter.
 *
 * Usage: DS2 <output_file> <1/Q> <level>
 *
 * Examples: 
 *
 *   DS2 sine.pcm 0
 *   DS2 sweep.pcm 200 600
 *
 * Output is raw PCM data, 44100 Hz/16 bit/Intel format (LSB,MSB)
 *
 * Copyright (c) Mikko Helin, 1999
 *
 */

// Include Headers
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dos.h>

// EG macros; Not Much Used Here
#define STOPPED 0
#define ATTACK 1
#define DECAY 2
#define SUSTAIN 3
#define RELEASE 4

// Some Other Constants
#define BLOCKSIZE 2048

// Store Data Here
static long dwSample[BLOCKSIZE];
static int wSample[BLOCKSIZE];

// Resonance:  Less Is More = 1/Q
static long dwQ=0x00000000;  // Zero Generates Sine Wave 

// Amplitude; 12 bits
static long dwEG2=0x0FFF;    // Amplitude Envelope; Constant Here


// DoSynth: Generates the Voice 
static void DoSynth(void);  



// Main function
/***************************************************************/
int main(int argc, char *argv[]) {
/***************************************************************/
    FILE *fp=0;
    char szFilename[32];
    char szQ[12];
    char szV[12];
    int cc=0;
    int i=0;

    if (argc>1)  // Output File Name
        strcpy(szFilename,argv[1]);
    else
        strcpy(szFilename,"synth.snd");

    if (argc>2) { // Resonance Setting; 1/Q; Zero Generates SineWave
        strcpy(szQ,argv[2]);
        dwQ=atol(szQ);
    }
    
    if (argc>3) { // Volume For DCA
        strcpy(szV,argv[3]);
        dwEG2=atol(szV);
    }

    if( !(fp = fopen(szFilename, "wb")) ) {
        printf("\t\007 Output File \"%s\" Not Created\n\n", szFilename);
        goto exit;
    }

    
    printf("DS2: Generating Sound File ...");
    for(i = 0; i < 0xFFFF/0x07FF; i++) {
        printf(".");
        DoSynth();
        cc = fwrite(wSample, 2, BLOCKSIZE, fp);
    }
    printf("\n");

    fclose(fp);
exit:

    return 0;
}

/***************************************************************/
void DoSynth() {
/***************************************************************/
//   DATA FORMAT: 20 bit + 12 bit fraction
    static long dwLP=0; // LP Output
    static long dwHP=0; // HP Output
    static long dwBP=0; // BP Output
//    static long dwNO=0;
    static long dwD0=0; // Not Used
    static long dwD1=0x00FFFFFF; // Delay 1
    static long dwD2=0x00FFFFFF; // Delay 2
    static long dwEG1=0;         // EG 1 Output For Filter
    static long  dwEG=0xFFFF;    // EG 1 "Phase"
    static unsigned int  wEG2=0xFFFF; // EG 2; not used
    static long  dwS=0;         // VCO Output to VCA
    static long  dwS0=0;        // "Phase"

    static int   wS=0x7FFF;     // not used
    static unsigned int wDec=0x000F;  // not used
    static long   dwDiff = (0x0000FFFF / (44100L/100L)); // VCO Increment
                                                    // For 100 Hz Saw
    static int    wDiff =  0xFFFF / (44100/100);   // not used
    register int i;               // Loop Counter
    static int wBufferSize=BLOCKSIZE; // Loop Size

    for (i=0; i<wBufferSize;i++) { 

            //---------------------------------------------------------
            // VCO
            // SAW Waveform Generation (With Aliasing!!)
            dwS0 += dwDiff;  // Generate Saw Wave Format
            if (dwS0 > 32000) 
                dwS0 = -32000;
            dwS = dwS0;

            if (dwQ == 0) // For Sine Wave Generation
                dwS = 0;


            //---------------------------------------------------------
            // EG1: FILTER EG
            dwEG--;  // 0 .. FFFF  = 64 ksamples = 1.5 sec up
            dwEG1 = dwEG >> 4;  // 16 to 12 bits

            //---------------------------------------------------------
            // EG2: AMP; Not Used; Constant; See Main
            //wEG2--;  // 0 .. FFFF  = 64 ksamples = 1.5 sec up
            //dwEG2 = wEG2>>4;  // 16 to 12 bits

            //---------------------------------------------------------
            // VCA: Amplifier
            dwS = (dwS * dwEG2)>>12;

            //---------------------------------------------------------
            // DSVF SECTION: Digital State Variable Filter
            // dwEG1 := 2*pi*Fc/Fs gets values 0 (Fc=0 Hz)..1 (Fc=Fs/(2*pi))
            // Low Pass Filter
            dwLP = dwD2 + (dwEG1*(dwD1>>12));

            // dwQ = 1/Q gets values 0 (infinite Q) .. 2 (Q=0.5)

            // High Pass Filter
            dwHP = ((dwS<<12) - dwLP) - (dwQ*(dwD1>>12));

            // Band Pass Filter
            dwBP = dwEG1*(dwHP>>12) + dwD1;

            // Notch Filter; Not Used Here
            // dwNO = dwHP + dwLP;  
            
            // Delay Lines
            dwD1 = dwBP;
            dwD2 = dwLP;

            //---------------------------------------------------------
            // OUTPUT
            // Truncate To 20 Bits
            dwS = dwLP >> 12;

            wSample[i] = dwS;

            // Overflow to Max/Min Values
            if (dwS > 32767L) 
                wSample[i] = 32767;
            if (dwS < -32767L)
                wSample[i] = -32767;
            
    }  // Buffer Done
} // DoSynth Done




More information about the Synth-diy mailing list