/* The original version of this program can be found at http://damb.dk */
#include <windows.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>

#define MY_PI 3.141593
#define SAMPLE_RATE 22050

#define A_NODE  440
#define As_NODE 466
#define B_NODE  494
#define C_NODE  523
#define Cs_NODE 554
#define D_NODE  587
#define Ds_Node 622
#define E_NODE  659
#define F_NODE  698
#define Fs_NODE 740
#define G_NODE  784
#define Gs_NODE 831

/* 440.000 466.163 493.883 523.251 554.365 587.329 622.253 659.255 698.456 739.988 783.991 830.609 */

void CALLBACK CallBackProc(HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
  if(uMsg == WOM_DONE)
  {
    MMRESULT MMResult;
    WAVEHDR *WaveHeader = (WAVEHDR *)dwParam1;

    if((MMResult = waveOutUnprepareHeader(hwo, WaveHeader, sizeof(WAVEHDR))) != MMSYSERR_NOERROR)
    {
      char Text[256];
      waveOutGetErrorText(MMResult, Text, sizeof(Text));
      printf("Failed to unprepare: %sn", Text);
    }

    free(WaveHeader->lpData);
  }
}

bool PlayTone(int freq, int duration)
{
  int x;
  char *buffer = (char *)malloc(SAMPLE_RATE*duration/1000);
  for (x = 0; x < SAMPLE_RATE*duration/1000; x++)
     buffer[x] = (char )(128.0 + (127.0 * sin(2.0 * MY_PI * freq * x / SAMPLE_RATE)));

  HWAVEOUT WaveHandle;
  WAVEFORMATEX WaveFormat;
  WAVEHDR WaveHeader;
  MMRESULT MMResult;

  WaveFormat.wFormatTag = WAVE_FORMAT_PCM;
  WaveFormat.nChannels = 1;
  WaveFormat.nSamplesPerSec = SAMPLE_RATE;
  WaveFormat.nAvgBytesPerSec = SAMPLE_RATE;
  WaveFormat.nBlockAlign = 1;
  WaveFormat.wBitsPerSample = 8;
  WaveFormat.cbSize = 0;

  if(waveOutOpen(&WaveHandle, WAVE_MAPPER, &WaveFormat, (DWORD )CallBackProc, 0, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
  {
    printf("Failed to open Wave!n");
    return false;
  }

  memset(&WaveHeader, 0, sizeof(WaveHeader));

  WaveHeader.lpData = buffer;
  WaveHeader.dwBufferLength = duration*SAMPLE_RATE/1000;
  WaveHeader.dwBytesRecorded = duration*SAMPLE_RATE/1000;
  WaveHeader.dwLoops = 1;
  WaveHeader.dwFlags = WHDR_BEGINLOOP | WHDR_ENDLOOP;
  if(waveOutPrepareHeader(WaveHandle, &WaveHeader, sizeof(WaveHeader)) != MMSYSERR_NOERROR)
  {
    printf("Failed to prepare header!n");
    return false;
  }

  if((MMResult = waveOutWrite(WaveHandle, &WaveHeader, sizeof(WaveHeader))) != MMSYSERR_NOERROR)
  {
    char Text[256];
    waveOutGetErrorText(MMResult, Text, sizeof(Text));
    printf("Failed to write: %sn", Text);
    return false;
  }
  Sleep(duration);
  while(!(WaveHeader.dwFlags & WHDR_DONE))
    Sleep(10);
  if((MMResult = waveOutClose(WaveHandle)) != MMSYSERR_NOERROR)
  {
    char Text[256];
    waveOutGetErrorText(MMResult, Text, sizeof(Text));
    printf("Failed to close: %sn", Text);
    return false;
  }
  return true;
}

int main(void)
{
  PlayTone(A_NODE, 1000);
  PlayTone(As_NODE, 1000);
  PlayTone(B_NODE, 1000);
  PlayTone(C_NODE, 1000);
  PlayTone(Cs_NODE, 1000);
  PlayTone(D_NODE, 1000);
  PlayTone(Ds_Node, 1000);
  PlayTone(E_NODE, 1000);
  PlayTone(F_NODE, 1000);
  PlayTone(Fs_NODE, 1000);
  PlayTone(G_NODE, 1000);
  PlayTone(Gs_NODE, 1000);
  return 0;
}