Click here to Skip to main content
15,891,529 members
Articles / Desktop Programming / MFC

Morse code. Some examples of how to produce sounds.

Rate me:
Please Sign up or sign in to vote.
4.64/5 (16 votes)
3 Apr 2001 132.5K   2.6K   66  
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


Written By
Web Developer SEO
Russian Federation Russian Federation
AlexF's Blog in Russian
Owner Spy competition analysis
Rating Burner Rating of blogs

Comments and Discussions