home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / pcmagazi / 1992 / 04 / addsynth.c < prev    next >
C/C++ Source or Header  |  1991-11-06  |  9KB  |  290 lines

  1. /*---------------------------------------------------
  2.    ADDSYNTH.C -- Additive Synthesis Sound Generation
  3.                  (c) Charles Petzold, 1992
  4.   ---------------------------------------------------*/
  5.  
  6. #include <windows.h>
  7. #include <mmsystem.h>
  8. #include <math.h>
  9. #include <stdio.h>
  10. #include <sys\types.h>
  11. #include <sys\stat.h>
  12. #include "addsynth.h"
  13.  
  14. #define ID_TIMER             1
  15. #define SAMPLE_RATE      22050
  16. #define MAX_PARTIALS        21
  17. #define PI             3.14159
  18.  
  19. BOOL FAR PASCAL DlgProc (HWND, WORD, WORD, LONG) ;
  20.  
  21. static char szAppName [] = "AddSynth" ;
  22.  
  23.           // Structures for storing instrument envelopes
  24.  
  25. typedef struct
  26.      {
  27.      int iTime ;
  28.      int iValue ;
  29.      }
  30.      ENV ;
  31.  
  32. typedef struct
  33.      {
  34.      int  iNumAmp ;
  35.      ENV *pEnvAmp ;
  36.      int  iNumFrq ;
  37.      ENV *pEnvFrq ;
  38.      }
  39.      PRT ;
  40.  
  41. typedef struct
  42.      {
  43.      int   iMsecTime ;
  44.      int   iNumPartials ;
  45.      PRT  *pprt ;
  46.      }
  47.      INS ;
  48.  
  49. #include "instdefs.h"
  50.  
  51.           // Sine Wave Generator
  52.  
  53. double SineGenerator (double dFreq, double *pdAngle)
  54.      {
  55.      double dAmp ;
  56.  
  57.      dAmp = sin (*pdAngle) ;
  58.      *pdAngle += 2 * PI * dFreq / SAMPLE_RATE ;
  59.  
  60.      if (*pdAngle >= 2 * PI)
  61.           *pdAngle -= 2 * PI ;
  62.  
  63.      return dAmp ;
  64.      }
  65.  
  66.           // Fill a Buffer with Composite Waveform
  67.  
  68. VOID FillBuffer (INS ins, PBYTE pBuffer, long lNumSamples)
  69.      {
  70.      static double dAngle [MAX_PARTIALS] ;
  71.      double        dAmp, dFrq, dComp, dFrac ;
  72.      int           i, iPrt, iMsecTime, iCompMaxAmp, iMaxAmp ;
  73.      long          lSmp ;
  74.  
  75.                // Calculate the composite maximum amplitude
  76.  
  77.      iCompMaxAmp = 0 ;
  78.  
  79.      for (iPrt = 0 ; iPrt < ins.iNumPartials ; iPrt++)
  80.           {
  81.           iMaxAmp = 0 ;
  82.  
  83.           for (i = 0 ; i < ins.pprt[iPrt].iNumAmp ; i++)
  84.                iMaxAmp = max (iMaxAmp, ins.pprt[iPrt].pEnvAmp[i].iValue) ;
  85.  
  86.           iCompMaxAmp += iMaxAmp ;
  87.           }
  88.  
  89.                // Loop through each sample
  90.  
  91.      for (lSmp = 0 ; lSmp < lNumSamples ; lSmp++)
  92.           {
  93.           dComp = 0 ;
  94.           iMsecTime = (int) (1000 * lSmp / SAMPLE_RATE) ;
  95.  
  96.                     // Loop through each partial
  97.  
  98.           for (iPrt = 0 ; iPrt < ins.iNumPartials ; iPrt++)
  99.                {
  100.                dAmp = 0 ;
  101.                dFrq = 0 ;
  102.  
  103.                for (i = 0 ; i < ins.pprt[iPrt].iNumAmp - 1 ; i++)
  104.                     {
  105.                     if (iMsecTime >= ins.pprt[iPrt].pEnvAmp[i  ].iTime &&
  106.                         iMsecTime <= ins.pprt[iPrt].pEnvAmp[i+1].iTime)
  107.                          {
  108.                          dFrac = (double) (iMsecTime -
  109.                                            ins.pprt[iPrt].pEnvAmp[i  ].iTime) /
  110.                                           (ins.pprt[iPrt].pEnvAmp[i+1].iTime -
  111.                                            ins.pprt[iPrt].pEnvAmp[i  ].iTime) ;
  112.  
  113.                          dAmp =   dFrac  * ins.pprt[iPrt].pEnvAmp[i+1].iValue +
  114.                                (1-dFrac) * ins.pprt[iPrt].pEnvAmp[i  ].iValue ;
  115.  
  116.                          break ;
  117.                          }
  118.                     }
  119.  
  120.                for (i = 0 ; i < ins.pprt[iPrt].iNumFrq - 1 ; i++)
  121.                     {
  122.                     if (iMsecTime >= ins.pprt[iPrt].pEnvFrq[i  ].iTime &&
  123.                         iMsecTime <= ins.pprt[iPrt].pEnvFrq[i+1].iTime)
  124.                          {
  125.                          dFrac = (double) (iMsecTime -
  126.                                            ins.pprt[iPrt].pEnvFrq[i  ].iTime) /
  127.                                           (ins.pprt[iPrt].pEnvFrq[i+1].iTime -
  128.                                            ins.pprt[iPrt].pEnvFrq[i  ].iTime) ;
  129.  
  130.                          dFrq =   dFrac  * ins.pprt[iPrt].pEnvFrq[i+1].iValue +
  131.                                (1-dFrac) * ins.pprt[iPrt].pEnvFrq[i  ].iValue ;
  132.  
  133.                          break ;
  134.                          }
  135.                     }
  136.  
  137.                dComp += dAmp * SineGenerator (dFrq, dAngle + iPrt) ;
  138.                }
  139.  
  140.           pBuffer[lSmp] = (BYTE) (127 + 127 * dComp / iCompMaxAmp) ;
  141.           }
  142.      }
  143.  
  144. BOOL CreateFile (INS ins, char *szFileName)
  145.      {
  146.      FILE          *file ;
  147.      int           iWrite ;
  148.      LOCALHANDLE   hLocal ;
  149.      long          lChunkSize, lPcmSize, lNumSamples ;
  150.      PBYTE         pBuffer ;
  151.      PCMWAVEFORMAT pcm ;
  152.  
  153.      if (NULL == (file = fopen (szFileName, "wb")))
  154.           return FALSE ;
  155.  
  156.      lNumSamples = ((long) ins.iMsecTime * SAMPLE_RATE / 1000 + 1) / 2 * 2 ;
  157.      lPcmSize    = sizeof (PCMWAVEFORMAT) ;
  158.      lChunkSize  = 12 + lPcmSize + 8 + lNumSamples ;
  159.  
  160.      if (NULL == (hLocal = LocalAlloc (LHND, (int) lNumSamples)))
  161.           {
  162.           fclose (file) ;
  163.           return FALSE ;
  164.           }
  165.  
  166.      pBuffer = LocalLock (hLocal) ;
  167.  
  168.      FillBuffer (ins, pBuffer, lNumSamples) ;
  169.  
  170.      pcm.wf.wFormatTag      = WAVE_FORMAT_PCM ;
  171.      pcm.wf.nChannels       = 1 ;
  172.      pcm.wf.nSamplesPerSec  = SAMPLE_RATE ;
  173.      pcm.wf.nAvgBytesPerSec = SAMPLE_RATE ;
  174.      pcm.wf.nBlockAlign     = 1 ;
  175.      pcm.wBitsPerSample     = 8 ;
  176.  
  177.      fwrite ("RIFF",       4,                      1, file) ;
  178.      fwrite (&lChunkSize,  4,                      1, file) ;
  179.      fwrite ("WAVEfmt ",   8,                      1, file) ;
  180.      fwrite (&lPcmSize,    4,                      1, file) ;
  181.      fwrite (&pcm,         sizeof (PCMWAVEFORMAT), 1, file) ;
  182.      fwrite ("data",       4,                      1, file) ;
  183.      fwrite (&lNumSamples, 4,                      1, file) ;
  184.  
  185.      iWrite = fwrite (pBuffer, (int) lNumSamples,  1, file) ;
  186.  
  187.      fclose (file) ;
  188.  
  189.      LocalUnlock (hLocal) ;
  190.      LocalFree (hLocal) ;
  191.  
  192.      if (iWrite != 1)
  193.           {
  194.           remove (szFileName) ;
  195.           return FALSE ;
  196.           }
  197.  
  198.      return TRUE ;
  199.      }
  200.  
  201. void TestAndCreateFile (HWND hwnd, INS ins, char *szFileName, int idButton)
  202.      {
  203.      char        szMessage [64] ;
  204.      struct stat st ;
  205.  
  206.      if (0 == stat (szFileName, &st))
  207.           EnableWindow (GetDlgItem (hwnd, idButton), TRUE) ;
  208.      else
  209.           {
  210.           if (CreateFile (ins, szFileName))
  211.                EnableWindow (GetDlgItem (hwnd, idButton), TRUE) ;
  212.           else
  213.                {
  214.                wsprintf (szMessage, "Could not create %x.", szFileName) ;
  215.                MessageBeep (MB_ICONEXCLAMATION) ;
  216.                MessageBox (hwnd, szMessage, szAppName,
  217.                            MB_OK | MB_ICONEXCLAMATION) ;
  218.                }
  219.           }
  220.      }
  221.  
  222. int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,
  223.                     LPSTR lpszCmdLine, int nCmdShow)
  224.      {
  225.      FARPROC lpDlgProc ;
  226.  
  227.      lpDlgProc = MakeProcInstance (DlgProc, hInstance) ;
  228.      DialogBox (hInstance, szAppName, NULL, lpDlgProc) ;
  229.      FreeProcInstance (lpDlgProc) ;
  230.  
  231.      return 0 ;
  232.      }
  233.  
  234. BOOL FAR PASCAL DlgProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)
  235.      {
  236.      static char *szTrum = "Trumpet.Wav" ;
  237.      static char *szOboe = "Oboe.Wav" ;
  238.      static char *szClar = "Clarinet.Wav" ;
  239.  
  240.      switch (message)
  241.           {
  242.           case WM_INITDIALOG:
  243.                SetTimer (hwnd, ID_TIMER, 1, NULL) ;
  244.                return TRUE ;
  245.  
  246.           case WM_TIMER:
  247.                KillTimer (hwnd, ID_TIMER) ;
  248.                SetCursor (LoadCursor (NULL, IDC_WAIT)) ;
  249.                ShowCursor (TRUE) ;
  250.  
  251.                TestAndCreateFile (hwnd, insTrum, szTrum, ID_TRUMPET) ;
  252.                TestAndCreateFile (hwnd, insOboe, szOboe, ID_OBOE) ;
  253.                TestAndCreateFile (hwnd, insClar, szClar, ID_CLARINET) ;
  254.  
  255.                SetDlgItemText (hwnd, ID_TEXT, " ") ;
  256.                SetFocus (GetDlgItem (hwnd, ID_TRUMPET)) ;
  257.  
  258.                ShowCursor (FALSE) ;
  259.                SetCursor (LoadCursor (NULL, IDC_ARROW)) ;
  260.                return TRUE ;
  261.  
  262.           case WM_COMMAND:
  263.                switch (wParam)
  264.                     {
  265.                     case ID_TRUMPET:
  266.                          sndPlaySound (szTrum, SND_SYNC) ;
  267.                          return TRUE ;
  268.  
  269.                     case ID_OBOE:
  270.                          sndPlaySound (szOboe, SND_SYNC) ;
  271.                          return TRUE ;
  272.  
  273.                     case ID_CLARINET:
  274.                          sndPlaySound (szClar, SND_SYNC) ;
  275.                          return TRUE ;
  276.                     }
  277.                break ;
  278.  
  279.           case WM_SYSCOMMAND:
  280.                switch (wParam)
  281.                     {
  282.                     case SC_CLOSE:
  283.                          EndDialog (hwnd, 0) ;
  284.                          return TRUE ;
  285.                     }
  286.                break ;
  287.           }
  288.      return FALSE ;
  289.      }
  290.