Audio playing and recording of MFC practical skills

Catalog

Audio playback

Playing MP3 and wav files

Play audio stream

Sound recording

Pcm format

Wav format

Audio playback

There are two ways to play the audio: playing the audio file directly and playing the audio stream. You can choose the use method according to the actual situation

Playing MP3 and wav files

The operation steps include: loading files, playing, pausing, resuming and stopping

  • Loading file
int Load(HWND hWnd, CString strFilepath)
{
	m_hWnd = hWnd;
	DWORD dwReturn;
	mciSendCommand(DeviceID, MCI_CLOSE, 0, 0);//Empty the last played device before loading the file
	mciopenparms.lpstrElementName = strFilepath;//Pass music file path to device
	mciopenparms.lpstrDeviceType = _T("mpegvideo");

	if (dwReturn = mciSendCommand(NULL, MCI_OPEN, MCI_OPEN_ELEMENT | MCI_OPEN_TYPE, (DWORD_PTR)&mciopenparms))
	{
		//If the file fails to be opened, the error message will be stored in the buffer and an error warning will be displayed
		CString s;
		s.Format(_T("error:%d!"), dwReturn);
		MessageBox(hWnd, s, _T("player"), MB_OKCANCEL);
	}
	DeviceID = mciopenparms.wDeviceID;

	return dwReturn;
}
  • play
void play()
{
	MCI_PLAY_PARMS mciplayparms;
	mciplayparms.dwCallback = (DWORD)m_hWnd;
	mciplayparms.dwFrom = 0;//dwFrom is used to set the starting position of music playing
	mciSendCommand(DeviceID, MCI_PLAY, MCI_FROM | MCI_NOTIFY, (DWORD_PTR)&mciplayparms);//dwCallback and MCI ﹣ notify are paired
}
  • suspend
void pause()
{
	mciSendCommand(DeviceID, MCI_PAUSE, 0, 0);
}
  • recovery
void resume()
{
	mciSendCommand(DeviceID, MCI_RESUME, 0, 0);
}
  • Stop it
void stop()
{
	mciSendCommand(DeviceID, MCI_STOP, 0, 0);//When the stop button is clicked, all information will be cleared
	mciSendCommand(DeviceID, MCI_CLOSE, 0, 0);//When you click the close button, clear the device information, and then click the play button to play no music

}
  • Set playback volume
DWORD setvolume(DWORD vol)
{
	MCI_DGV_SETAUDIO_PARMS setvolume;//This is the parameter data structure for setting the volume
	setvolume.dwCallback = NULL;
	setvolume.dwItem = MCI_DGV_SETAUDIO_VOLUME;//The action is to set the volume
	setvolume.dwValue = vol;//Volume value is vol
	mciSendCommand(DeviceID, MCI_SETAUDIO, MCI_DGV_SETAUDIO_ITEM | MCI_DGV_SETAUDIO_VALUE, (DWORD)(LPVOID)&setvolume);
	return 0;
}

See the loading file steps for DeviceID

Play audio stream

Playing the audio stream, I have encapsulated it into a simple class WaveOut, which can be directly ported for use, including opening, closing, push ing audio data, etc. see the source code for details

  • Open a playback entity

HWAVEOUT hWaveOut;
WAVEHDR wvHeader[2];

int WaveOut::open(DWORD nSamplesPerSec, WORD wBitsPerSample, WORD nChannels)
{
        /*
        ...
        See source code for details
        */

	/* 'waveOutOpen' will call 'SetEvent'. */
	if (waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, (DWORD_PTR)hEventPlay, 0, CALLBACK_EVENT))
	{
		return -1;
	}

	waveOutPrepareHeader(hWaveOut, &wvHeader[0], sizeof(WAVEHDR));
	waveOutPrepareHeader(hWaveOut, &wvHeader[1], sizeof(WAVEHDR));

        /*
        ...
        */

	return 0;
}

 

In this step, we need to add two bufs to waveIn. As for why they are two, only when there is at least one buf in the queue, there will be no broken tone. The actual measurement is true.

  • Close a playback entity
void WaveOut::close()
{
    waveOutUnprepareHeader(hWaveOut, &wvHeader[0], sizeof(WAVEHDR));
    waveOutUnprepareHeader(hWaveOut, &wvHeader[1], sizeof(WAVEHDR));
    waveOutClose(hWaveOut);
    hWaveOut = NULL;
}
  • Push data

After playing a buf in the queue, use the waveOutWrite interface to reload the input data

Sound recording

Playing the audio stream, I have encapsulated it into a simple class WaveIn, which can be directly ported for use. The class includes opening, closing, starting recording and pausing. See the source code for details

  • Open a recording entity

WAVEHDR wvHeader[2];
HWAVEIN hWaveIn;

int WaveIn::open(DWORD nSamplesPerSec, WORD wBitsPerSample, WORD nChannels)
{
        /*
        .
        .See source code for details
        .
        */

	//waveInReset(hWaveIn);
	waveInPrepareHeader(hWaveIn, &wvHeader[0], sizeof(WAVEHDR));
	waveInPrepareHeader(hWaveIn, &wvHeader[1], sizeof(WAVEHDR));

	//Add two whdrs to waveIn
	waveInAddBuffer(hWaveIn, &wvHeader[0], sizeof(WAVEHDR));
	waveInAddBuffer(hWaveIn, &wvHeader[1], sizeof(WAVEHDR));

	iCurRecording = 0;

	return 0;
}
  • Close a recording entity
void WaveIn::close()
{
    waveInStop(hWaveIn);
    waveInUnprepareHeader(hWaveIn, &wvHeader[0], sizeof(WAVEHDR));
    waveInUnprepareHeader(hWaveIn, &wvHeader[1], sizeof(WAVEHDR));
    waveInClose(hWaveIn);
    hWaveIn = NULL;
}
  • Recording begins
int WaveIn::record_start()
{
	waveInStart(hWaveIn);
	return 0;
}
  • Recording stop
int WaveIn::record_stop()
{
	waveInStop(hWaveIn);
	return 0;
}

Pcm format

It can store pcm format and directly write the recording data into the file

Wav format

typedef struct wav_format_t {
	char riff[4];//"RIFF"
	unsigned int file_len;
	char wav_type[4];//"WAVE"
	char fmt[4];//"fmt "
	unsigned int fmt_len;
	unsigned short wFormatTag;
	unsigned short nChannels;
	unsigned int nSamplesPerSec;
	unsigned int nAvgBytesPerSec;
	unsigned short nBlockAlign;
	unsigned short wBitsPerSample;
	char dataFlag[4];//"data"
	unsigned int data_len;
} wav_format;

When storing wav format, you need to store the above structure in the header of the file. Note that the length of the structure is file size minus 4, and the length of data is file size minus appeal structure size, that is, the size of effective audio. These two values can only be determined after recording

After the appeal header is stored, the later data is stored in the same way as pcm

Related materials including demo code can be downloaded from the bottom link of my < MFC practical skills > Article!

 

Published 33 original articles, won praise 26, visited 10000+
Private letter follow

Posted on Fri, 13 Mar 2020 22:42:23 -0700 by bgomillion