home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
pcmagazi
/
1992
/
04
/
addsynth.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-11-06
|
9KB
|
290 lines
/*---------------------------------------------------
ADDSYNTH.C -- Additive Synthesis Sound Generation
(c) Charles Petzold, 1992
---------------------------------------------------*/
#include <windows.h>
#include <mmsystem.h>
#include <math.h>
#include <stdio.h>
#include <sys\types.h>
#include <sys\stat.h>
#include "addsynth.h"
#define ID_TIMER 1
#define SAMPLE_RATE 22050
#define MAX_PARTIALS 21
#define PI 3.14159
BOOL FAR PASCAL DlgProc (HWND, WORD, WORD, LONG) ;
static char szAppName [] = "AddSynth" ;
// Structures for storing instrument envelopes
typedef struct
{
int iTime ;
int iValue ;
}
ENV ;
typedef struct
{
int iNumAmp ;
ENV *pEnvAmp ;
int iNumFrq ;
ENV *pEnvFrq ;
}
PRT ;
typedef struct
{
int iMsecTime ;
int iNumPartials ;
PRT *pprt ;
}
INS ;
#include "instdefs.h"
// Sine Wave Generator
double SineGenerator (double dFreq, double *pdAngle)
{
double dAmp ;
dAmp = sin (*pdAngle) ;
*pdAngle += 2 * PI * dFreq / SAMPLE_RATE ;
if (*pdAngle >= 2 * PI)
*pdAngle -= 2 * PI ;
return dAmp ;
}
// Fill a Buffer with Composite Waveform
VOID FillBuffer (INS ins, PBYTE pBuffer, long lNumSamples)
{
static double dAngle [MAX_PARTIALS] ;
double dAmp, dFrq, dComp, dFrac ;
int i, iPrt, iMsecTime, iCompMaxAmp, iMaxAmp ;
long lSmp ;
// Calculate the composite maximum amplitude
iCompMaxAmp = 0 ;
for (iPrt = 0 ; iPrt < ins.iNumPartials ; iPrt++)
{
iMaxAmp = 0 ;
for (i = 0 ; i < ins.pprt[iPrt].iNumAmp ; i++)
iMaxAmp = max (iMaxAmp, ins.pprt[iPrt].pEnvAmp[i].iValue) ;
iCompMaxAmp += iMaxAmp ;
}
// Loop through each sample
for (lSmp = 0 ; lSmp < lNumSamples ; lSmp++)
{
dComp = 0 ;
iMsecTime = (int) (1000 * lSmp / SAMPLE_RATE) ;
// Loop through each partial
for (iPrt = 0 ; iPrt < ins.iNumPartials ; iPrt++)
{
dAmp = 0 ;
dFrq = 0 ;
for (i = 0 ; i < ins.pprt[iPrt].iNumAmp - 1 ; i++)
{
if (iMsecTime >= ins.pprt[iPrt].pEnvAmp[i ].iTime &&
iMsecTime <= ins.pprt[iPrt].pEnvAmp[i+1].iTime)
{
dFrac = (double) (iMsecTime -
ins.pprt[iPrt].pEnvAmp[i ].iTime) /
(ins.pprt[iPrt].pEnvAmp[i+1].iTime -
ins.pprt[iPrt].pEnvAmp[i ].iTime) ;
dAmp = dFrac * ins.pprt[iPrt].pEnvAmp[i+1].iValue +
(1-dFrac) * ins.pprt[iPrt].pEnvAmp[i ].iValue ;
break ;
}
}
for (i = 0 ; i < ins.pprt[iPrt].iNumFrq - 1 ; i++)
{
if (iMsecTime >= ins.pprt[iPrt].pEnvFrq[i ].iTime &&
iMsecTime <= ins.pprt[iPrt].pEnvFrq[i+1].iTime)
{
dFrac = (double) (iMsecTime -
ins.pprt[iPrt].pEnvFrq[i ].iTime) /
(ins.pprt[iPrt].pEnvFrq[i+1].iTime -
ins.pprt[iPrt].pEnvFrq[i ].iTime) ;
dFrq = dFrac * ins.pprt[iPrt].pEnvFrq[i+1].iValue +
(1-dFrac) * ins.pprt[iPrt].pEnvFrq[i ].iValue ;
break ;
}
}
dComp += dAmp * SineGenerator (dFrq, dAngle + iPrt) ;
}
pBuffer[lSmp] = (BYTE) (127 + 127 * dComp / iCompMaxAmp) ;
}
}
BOOL CreateFile (INS ins, char *szFileName)
{
FILE *file ;
int iWrite ;
LOCALHANDLE hLocal ;
long lChunkSize, lPcmSize, lNumSamples ;
PBYTE pBuffer ;
PCMWAVEFORMAT pcm ;
if (NULL == (file = fopen (szFileName, "wb")))
return FALSE ;
lNumSamples = ((long) ins.iMsecTime * SAMPLE_RATE / 1000 + 1) / 2 * 2 ;
lPcmSize = sizeof (PCMWAVEFORMAT) ;
lChunkSize = 12 + lPcmSize + 8 + lNumSamples ;
if (NULL == (hLocal = LocalAlloc (LHND, (int) lNumSamples)))
{
fclose (file) ;
return FALSE ;
}
pBuffer = LocalLock (hLocal) ;
FillBuffer (ins, pBuffer, lNumSamples) ;
pcm.wf.wFormatTag = WAVE_FORMAT_PCM ;
pcm.wf.nChannels = 1 ;
pcm.wf.nSamplesPerSec = SAMPLE_RATE ;
pcm.wf.nAvgBytesPerSec = SAMPLE_RATE ;
pcm.wf.nBlockAlign = 1 ;
pcm.wBitsPerSample = 8 ;
fwrite ("RIFF", 4, 1, file) ;
fwrite (&lChunkSize, 4, 1, file) ;
fwrite ("WAVEfmt ", 8, 1, file) ;
fwrite (&lPcmSize, 4, 1, file) ;
fwrite (&pcm, sizeof (PCMWAVEFORMAT), 1, file) ;
fwrite ("data", 4, 1, file) ;
fwrite (&lNumSamples, 4, 1, file) ;
iWrite = fwrite (pBuffer, (int) lNumSamples, 1, file) ;
fclose (file) ;
LocalUnlock (hLocal) ;
LocalFree (hLocal) ;
if (iWrite != 1)
{
remove (szFileName) ;
return FALSE ;
}
return TRUE ;
}
void TestAndCreateFile (HWND hwnd, INS ins, char *szFileName, int idButton)
{
char szMessage [64] ;
struct stat st ;
if (0 == stat (szFileName, &st))
EnableWindow (GetDlgItem (hwnd, idButton), TRUE) ;
else
{
if (CreateFile (ins, szFileName))
EnableWindow (GetDlgItem (hwnd, idButton), TRUE) ;
else
{
wsprintf (szMessage, "Could not create %x.", szFileName) ;
MessageBeep (MB_ICONEXCLAMATION) ;
MessageBox (hwnd, szMessage, szAppName,
MB_OK | MB_ICONEXCLAMATION) ;
}
}
}
int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,
LPSTR lpszCmdLine, int nCmdShow)
{
FARPROC lpDlgProc ;
lpDlgProc = MakeProcInstance (DlgProc, hInstance) ;
DialogBox (hInstance, szAppName, NULL, lpDlgProc) ;
FreeProcInstance (lpDlgProc) ;
return 0 ;
}
BOOL FAR PASCAL DlgProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)
{
static char *szTrum = "Trumpet.Wav" ;
static char *szOboe = "Oboe.Wav" ;
static char *szClar = "Clarinet.Wav" ;
switch (message)
{
case WM_INITDIALOG:
SetTimer (hwnd, ID_TIMER, 1, NULL) ;
return TRUE ;
case WM_TIMER:
KillTimer (hwnd, ID_TIMER) ;
SetCursor (LoadCursor (NULL, IDC_WAIT)) ;
ShowCursor (TRUE) ;
TestAndCreateFile (hwnd, insTrum, szTrum, ID_TRUMPET) ;
TestAndCreateFile (hwnd, insOboe, szOboe, ID_OBOE) ;
TestAndCreateFile (hwnd, insClar, szClar, ID_CLARINET) ;
SetDlgItemText (hwnd, ID_TEXT, " ") ;
SetFocus (GetDlgItem (hwnd, ID_TRUMPET)) ;
ShowCursor (FALSE) ;
SetCursor (LoadCursor (NULL, IDC_ARROW)) ;
return TRUE ;
case WM_COMMAND:
switch (wParam)
{
case ID_TRUMPET:
sndPlaySound (szTrum, SND_SYNC) ;
return TRUE ;
case ID_OBOE:
sndPlaySound (szOboe, SND_SYNC) ;
return TRUE ;
case ID_CLARINET:
sndPlaySound (szClar, SND_SYNC) ;
return TRUE ;
}
break ;
case WM_SYSCOMMAND:
switch (wParam)
{
case SC_CLOSE:
EndDialog (hwnd, 0) ;
return TRUE ;
}
break ;
}
return FALSE ;
}