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