Click here to Skip to main content
Click here to Skip to main content
 
Add your own
alternative version

Morse code. Some examples of how to produce sounds.

, 3 Apr 2001
Several classes demonstrating how to fill audio buffer and how to produce sound using waveOut* API
// AlexfSnd.cpp: implementation of the CAlexfSyncPlay class.
// Part of "Morse" project. (C) Alexander Fedorov, 2000. lamer2000@hotmail.com
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "AlexfSnd.h"
#include <math.h>
#include <stdio.h>

//define ALEXF_DEBUG_TRACE(buf) {FILE * f = fopen ("c:\\_trace.txt", "a"); fprintf (f, buf); fclose (f);}

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CAlexfSyncPlay::CAlexfSyncPlay(BOOL bSoundOn)
{
	SPS = 44100;						// Samples Per Sec
	dDuration = 0;						// duration, sec
	dFreq = 0;							// frequency
	wfme.wFormatTag = WAVE_FORMAT_PCM;	// general format
	wfme.nChannels = 1;					// 1 channel
	wfme.nSamplesPerSec = SPS;			// 
	wfme.nAvgBytesPerSec = SPS;			// 
	wfme.nBlockAlign = 1;				// 
	wfme.wBitsPerSample = 8;			// 
	wfme.cbSize = 0;					// additional info
}

CAlexfSyncPlay::~CAlexfSyncPlay()
{
}

void CALLBACK CAlexfSyncPlay::WaveOut_waveOutProc(
HWAVEOUT hwo, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
}


void CAlexfSyncPlay::FillSinus08(
unsigned char * pBuf,
int iBufLen,
int iSPS,
double fFreq)
{
	double dKoef = 2 * 3.1416 / iSPS * fFreq;
	for (int i=0; i<iBufLen; i++)
	pBuf[i] = (unsigned char) (cos(i * dKoef) * 125 + 127);
}

BOOL CAlexfSyncPlay::Beep()
{
	mmres = waveOutOpen(&hwout, WAVE_MAPPER, &wfme,
	(DWORD) WaveOut_waveOutProc, 0x12345, CALLBACK_FUNCTION);
	if (mmres != MMSYSERR_NOERROR)
	{
		delete [] WaveBuf;
		return FALSE;
	}
	whdr.lpData = WaveBuf;
	whdr.dwBufferLength = (DWORD) (dDuration * SPS);
//	whdr.dwFlags = WHDR_BEGINLOOP;
	mmres = waveOutPrepareHeader(hwout, & whdr, sizeof(whdr));
	if (mmres != MMSYSERR_NOERROR)
	{
		mmres = waveOutClose(hwout);
		delete [] WaveBuf;
		return FALSE;
	}
	whdr.dwLoops = 0;
	mmres = waveOutWrite(hwout, & whdr, sizeof(WAVEHDR));
	if (mmres == MMSYSERR_NOERROR)
	{
		while (!(whdr.dwFlags & WHDR_DONE))
			Sleep(1);
	}
	mmres = waveOutUnprepareHeader(hwout, & whdr, sizeof(WAVEHDR));
	mmres = waveOutClose(hwout);
	delete [] WaveBuf;
	return TRUE;
}

BOOL CAlexfSyncPlay::Beep08(double Freq, double Delay)
{
	dDuration = Delay;
	dFreq = Freq;
	WaveBuf = new char[(int)((double) SPS * dDuration)];
	if (WaveBuf == NULL) return FALSE;
	wfme.nAvgBytesPerSec = SPS;
	wfme.nBlockAlign = 1;
	wfme.wBitsPerSample  = 8;
	ZeroMemory(&whdr, sizeof(whdr));
	FillSinus08((unsigned char *) WaveBuf,
	(int) (dDuration * SPS), SPS, dFreq);
	return Beep();
}

//////////////////////////////////////////////
//////////////////////////////////////////////

CAlexfAsyncPlay2 * CAlexfAsyncPlay2::ziz = NULL;

CAlexfAsyncPlay2::CAlexfAsyncPlay2()
{
	bOK = FALSE;
	ziz = this;
	pcm = new CAlexfPCM[ALEXF_PLAY_BUF];
	if (!pcm) return;

    SPS = ALEXF_PLAY_SPS;
	wfme.wFormatTag = WAVE_FORMAT_PCM;
	wfme.nChannels = 1;
	wfme.nSamplesPerSec = SPS;
	wfme.nAvgBytesPerSec = SPS;
	wfme.nBlockAlign = 1;
	wfme.wBitsPerSample = 8;
	wfme.cbSize = 0;
	hwout = NULL;
	mmres = waveOutOpen(&hwout, WAVE_MAPPER, &wfme,
	(DWORD) CallbackWaveOutProc, 0x12345, CALLBACK_FUNCTION);
	if (mmres != MMSYSERR_NOERROR) return;

	bOK = TRUE;
}

CAlexfAsyncPlay2::~CAlexfAsyncPlay2()
{
	while (GetBusyBufferNumber() > 0)
	{
		Sleep(1);
		MSG msg;
		while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

 	if (hwout != NULL) mmres = waveOutClose(hwout);
	if (pcm) delete [] pcm;
}

BOOL CAlexfAsyncPlay2::AddSingleSound(long Freq, double Delay)
{
	BOOL bRC = FALSE;
	if (!bOK) return FALSE;
	if (Delay > 1) return FALSE;
	int i = GetFreeBuf();
	if (i < 0) return FALSE;
	bRC = TRUE;
	pcm[i].lFreq = Freq;
	pcm[i].dDelay = Delay;
	pcm[i].whdr.dwFlags = 0;
	pcm[i].CreateSinus08Sample();
	mmres = waveOutPrepareHeader(hwout, & pcm[i].whdr, sizeof(WAVEHDR));
	if (mmres != MMSYSERR_NOERROR) {ASSERT(0); bOK = FALSE;}
	mmres = waveOutWrite(hwout, & pcm[i].whdr, sizeof(WAVEHDR));
	if (mmres != MMSYSERR_NOERROR) {ASSERT(0); bOK = FALSE;}
	return bRC;
}

void CALLBACK CAlexfAsyncPlay2::CallbackWaveOutProc(HWAVEOUT hwo,
UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
	if (uMsg != WOM_DONE) return;
	MMRESULT mmres;
	mmres = waveOutUnprepareHeader(hwo, (WAVEHDR *) dwParam1, sizeof(WAVEHDR));
	if (mmres != MMSYSERR_NOERROR) {ASSERT(0); ziz->bOK = FALSE;}
	ziz->ReleaseBuf((WAVEHDR *) dwParam1);
}

void CAlexfAsyncPlay2::ReleaseBuf(WAVEHDR * lpwhdr)
{
	for (int i = 0; i < ALEXF_PLAY_BUF; i++)
	{
		if (pcm[i].iStage == PCM_STAGE_PLAY_NOW)
		if (lpwhdr == & pcm[i].whdr)
		{
			pcm[i].iStage = PCM_STAGE_FREE;
			return;
		}
	}
}

int CAlexfAsyncPlay2::GetFreeBuf()
{
	for (int i = 0; i < ALEXF_PLAY_BUF; i++)
	if (pcm[i].iStage == PCM_STAGE_FREE) return i;
	return -1;
}

int CAlexfAsyncPlay2::GetBusyBufferNumber()
{
	int iRC = 0;
	for (int i = 0; i < ALEXF_PLAY_BUF; i++)
	if (pcm[i].iStage == PCM_STAGE_PLAY_NOW) iRC++;
	return iRC;
}

////////////////////////////////////////////////////////////

CAlexfAsyncPlay* CAlexfAsyncPlay::ziz = NULL;

CAlexfAsyncPlay::CAlexfAsyncPlay()
{
	bOK = FALSE;
	ziz = this;
	bStopThreadNow = FALSE;
	pcm = new CAlexfPCM[ALEXF_PLAY_BUF];
	if (!pcm) return;
	lLastPCM = -1;

	InitializeCriticalSection(&csCriticalSection);
	// thread init
	DWORD dwThreadID = 0;
	hThread = ::CreateThread(NULL, 0,
	CAlexfAsyncPlay::ThreadFunc, (LPVOID) this, CREATE_SUSPENDED, &dwThreadID);
	if (hThread == NULL) {ASSERT(0); return;}
	ResumeThread(hThread);
	// wave init
    SPS = ALEXF_PLAY_SPS;
	wfme.wFormatTag = WAVE_FORMAT_PCM;
	wfme.nChannels = 1;
	wfme.nSamplesPerSec = SPS;
	wfme.nAvgBytesPerSec = SPS;
	wfme.nBlockAlign = 1;
	wfme.wBitsPerSample = 8;
	wfme.cbSize = 0;
	hwout = NULL;
	mmres = waveOutOpen(&hwout, WAVE_MAPPER, &wfme,
	(DWORD) CallbackWaveOutProc, 0x12345, CALLBACK_FUNCTION);
	if (mmres != MMSYSERR_NOERROR) return;
	bOK = TRUE;
}

CAlexfAsyncPlay::~CAlexfAsyncPlay()
{
	StopThread();
 	if (hwout != NULL) mmres = waveOutClose(hwout);
	DeleteCriticalSection(&csCriticalSection);
	if (pcm) delete [] pcm;
}

BOOL CAlexfAsyncPlay::StopThread()
{
	if (!hThread) return TRUE;
	bStopThreadNow = TRUE;
	DWORD dw = WaitForSingleObject(hThread, 1000 * 60);
	if (dw != WAIT_OBJECT_0) return FALSE;
	return TRUE;
}

BOOL CAlexfAsyncPlay::AddSingleSound(long Freq, double Delay)
{
	if (!bOK) return FALSE;
	BOOL bRC = FALSE;
	EnterCriticalSection(&csCriticalSection);
//	ALEXF_DEBUG_TRACE("AddSingleSound\n");
	if (lLastPCM != -1)
	{
		int i = lLastPCM;
		if (pcm[i].dDelay + Delay <= 1)
		{
			bRC = TRUE;
			pcm[i].FillSinus08(pcm[i].WaveBuf + (int)(pcm[i].dDelay  * ALEXF_PLAY_SPS), (int)(Delay * ALEXF_PLAY_SPS),
			ALEXF_PLAY_SPS, Freq);
			pcm[i].dDelay += Delay;
			pcm[i].whdr.dwBufferLength = (DWORD) (pcm[i].dDelay * ALEXF_PLAY_SPS);
			if (pcm[i].dDelay > 0.1)
			{
				pcm[i].iStage = PCM_STAGE_MARK_TO_FILL;
				lLastPCM = -1;
			}
			LeaveCriticalSection(&csCriticalSection);
			return bRC;
		}
	}
	int i = GetFreeBuf();
	if ((i >= 0) && (Delay <= 1))
	{
		bRC = TRUE;
		pcm[i].lFreq = Freq;
		pcm[i].dDelay = Delay;
		pcm[i].whdr.dwFlags = 0;
		pcm[i].FillSinus08(pcm[i].WaveBuf, (int)(pcm[i].dDelay * ALEXF_PLAY_SPS),
		ALEXF_PLAY_SPS, pcm[i].lFreq);
		pcm[i].whdr.lpData = pcm[i].WaveBuf;
		pcm[i].whdr.dwBufferLength = (DWORD) (pcm[i].dDelay * ALEXF_PLAY_SPS);
		if (pcm[i].dDelay > 0.1)
		{
			pcm[i].iStage = PCM_STAGE_MARK_TO_FILL;
		}
		else
		{
			lLastPCM = i;
		}
	}
	else
	{
//		ALEXF_DEBUG_TRACE("AddSingleSound - fail\n");
	}
	LeaveCriticalSection(&csCriticalSection);
	if (!bRC) Sleep(1);
	return bRC;
}

int CAlexfAsyncPlay::GetBusyBufferNumber()
{
	int iRC = 0;
	for (int i = 0; i < ALEXF_PLAY_BUF; i++)
	if (pcm[i].iStage == PCM_STAGE_PLAY_NOW) iRC++;
	return iRC;
}

DWORD WINAPI CAlexfAsyncPlay::ThreadFunc(LPVOID lpThreadParameter)
{
	BOOL bFirtTime = TRUE;
	MMRESULT mmres;
	ziz = (CAlexfAsyncPlay *) lpThreadParameter;
	while (!ziz->bStopThreadNow)
	{
		for (int i = 0; i < ALEXF_PLAY_BUF; i++)
		if (ziz->pcm[i].iStage == PCM_STAGE_MARK_TO_FILL)
		{
//			char ccc[256];	sprintf(ccc, "Delay [%ld] %.02f\n", i, ziz->pcm[i].dDelay);	ALEXF_DEBUG_TRACE(ccc);
			// add buffer
			EnterCriticalSection(&ziz->csCriticalSection);
			mmres = waveOutPrepareHeader(ziz->hwout, & ziz->pcm[i].whdr, sizeof(WAVEHDR));
			if (mmres != MMSYSERR_NOERROR) {ASSERT(0); ziz->bOK = FALSE;}
			mmres = waveOutWrite(ziz->hwout, & ziz->pcm[i].whdr, sizeof(WAVEHDR));
			if (mmres != MMSYSERR_NOERROR) {ASSERT(0); ziz->bOK = FALSE;}
			ziz->pcm[i].iStage = PCM_STAGE_PLAY_NOW;
			bFirtTime = FALSE;
			LeaveCriticalSection(&ziz->csCriticalSection);
		}
		while (ziz->GetBusyBufferNumber() >= ALEXF_PLAY_BUF)
		{
			Sleep(1);
		}
		EnterCriticalSection(&ziz->csCriticalSection);
		if (ziz->GetBusyBufferNumber() == 0)
		if (ziz->lLastPCM != -1)
		if (!bFirtTime)
		{
			int i = ziz->lLastPCM;
			ziz->lLastPCM = -1;
			mmres = waveOutPrepareHeader(ziz->hwout, & ziz->pcm[i].whdr, sizeof(WAVEHDR));
			if (mmres != MMSYSERR_NOERROR) {ASSERT(0); ziz->bOK = FALSE;}
			mmres = waveOutWrite(ziz->hwout, & ziz->pcm[i].whdr, sizeof(WAVEHDR));
			if (mmres != MMSYSERR_NOERROR) {ASSERT(0); ziz->bOK = FALSE;}
			ziz->pcm[i].iStage = PCM_STAGE_PLAY_NOW;
//			char ccc[256]; sprintf(ccc, "Delay2 [%ld] %.02f\n", i, ziz->pcm[i].dDelay); ALEXF_DEBUG_TRACE(ccc);
		}
		LeaveCriticalSection(&ziz->csCriticalSection);
	}
	// exit
	while (ziz->GetBusyBufferNumber() > 0)
	{
		Sleep(1);
		MSG msg;
		while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}
	return 0;
}

void CALLBACK CAlexfAsyncPlay::CallbackWaveOutProc(HWAVEOUT hwo,
UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
	if (uMsg != WOM_DONE) return;
	EnterCriticalSection(&ziz->csCriticalSection);
	MMRESULT mmres;
	mmres = waveOutUnprepareHeader(hwo, (WAVEHDR *) dwParam1, sizeof(WAVEHDR));
	if (mmres != MMSYSERR_NOERROR) {ASSERT(0); ziz->bOK = FALSE;}
	ziz->ReleaseBuf((WAVEHDR *) dwParam1);
//	ALEXF_DEBUG_TRACE("ReleaseBuf\n");
	LeaveCriticalSection(&ziz->csCriticalSection);
}

void CAlexfAsyncPlay::ReleaseBuf(WAVEHDR * lpwhdr)
{
	for (int i = 0; i < ALEXF_PLAY_BUF; i++)
	{
		if (pcm[i].iStage == PCM_STAGE_PLAY_NOW)
		if (lpwhdr == & pcm[i].whdr)
		{
			pcm[i].iStage = PCM_STAGE_FREE;
		}
	}
}

int CAlexfAsyncPlay::GetFreeBuf()
{
	for (int i = 0; i < ALEXF_PLAY_BUF; i++)
	if (pcm[i].iStage == PCM_STAGE_FREE) return i;
	return -1;
}

/////////////////////////////////////////

CAlexfPCM::CAlexfPCM()
{
	WaveBuf = new char[ALEXF_PLAY_SPS];
	if (!WaveBuf) return;
	ZeroMemory(WaveBuf, sizeof(WaveBuf));
	ZeroMemory(&whdr, sizeof(whdr));
	iStage = PCM_STAGE_FREE;
	lFreq = 0;
	dDelay = 0;
	lNext = -1;
}

CAlexfPCM::~CAlexfPCM()
{
	if (WaveBuf) delete [] WaveBuf;
}

BOOL CAlexfPCM::ResizeBuf(long lNewSize)
{
	BOOL bRC = TRUE;
	if (WaveBuf) delete [] WaveBuf;
	lFreq = 0;
	dDelay = 0;
	WaveBuf = new char[lNewSize];
	if (!WaveBuf) bRC = FALSE;
	else ZeroMemory(WaveBuf, lNewSize);
	return bRC;
}

void CAlexfPCM::FillSinus08(
char * pBuf,
int iBufLen,
int iSPS,
double fFreq)
{
	double dKoef = 2 * 3.1416 / iSPS * fFreq;
	for (int i=0; i<iBufLen; i++)
	pBuf[i] = (char) (cos(i * dKoef) * 125 + 127);
}

BOOL CAlexfPCM::CreateSinus08Sample()
{
	FillSinus08(WaveBuf, (int)(dDelay * ALEXF_PLAY_SPS),
	ALEXF_PLAY_SPS, lFreq);
	whdr.lpData = WaveBuf;
	whdr.dwBufferLength = (DWORD) (dDelay * ALEXF_PLAY_SPS);
	iStage = PCM_STAGE_PLAY_NOW;
	return TRUE;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Alexander Fedorov
Web Developer SEO
Ukraine Ukraine
AlexF's Blog in Russian
Owner Spy competition analysis
Rating Burner Rating of blogs

| Advertise | Privacy | Mobile
Web01 | 2.8.140721.1 | Last Updated 4 Apr 2001
Article Copyright 2001 by Alexander Fedorov
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid