我如何在Windows(32位和64位,直至Windows 7)上播放本機具有給定幅度和給定頻率的聲音(例如,由頻率2 kHz和3 kHz組成)?在Windows上播放任意聲音?
(通過原生我的意思是不使用外部庫)。
我相信這需要waveOutWrite方法,但我不知道它是如何工作的。
我如何在Windows(32位和64位,直至Windows 7)上播放本機具有給定幅度和給定頻率的聲音(例如,由頻率2 kHz和3 kHz組成)?在Windows上播放任意聲音?
(通過原生我的意思是不使用外部庫)。
我相信這需要waveOutWrite方法,但我不知道它是如何工作的。
我得到的東西的工作...
#define _USE_MATH_DEFINES 1
#include <math.h>
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <mmreg.h>
#include <complex>
#pragma comment(lib, "Winmm.lib")
MMRESULT play(float nSeconds,
float signal(float timeInSeconds, unsigned short channel, void *context),
void *context = NULL, unsigned long samplesPerSecond = 48000)
{
UINT timePeriod = 1;
MMRESULT mmresult = MMSYSERR_NOERROR;
WAVEFORMATEX waveFormat = {0};
waveFormat.cbSize = 0;
waveFormat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
waveFormat.nChannels = 2;
waveFormat.nSamplesPerSec = samplesPerSecond;
const size_t nBuffer =
(size_t)(nSeconds * waveFormat.nChannels * waveFormat.nSamplesPerSec);
float *buffer;
waveFormat.wBitsPerSample = CHAR_BIT * sizeof(buffer[0]);
waveFormat.nBlockAlign =
waveFormat.nChannels * waveFormat.wBitsPerSample/CHAR_BIT;
waveFormat.nAvgBytesPerSec =
waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
buffer = (float *)calloc(nBuffer, sizeof(*buffer));
__try
{
for (size_t i = 0; i < nBuffer; i += waveFormat.nChannels)
for (unsigned short j = 0; j < waveFormat.nChannels; j++)
buffer[i+j] = signal((i+j) * nSeconds/nBuffer, j, context);
HWAVEOUT hWavOut = NULL;
mmresult = waveOutOpen(&hWavOut, WAVE_MAPPER,
&waveFormat, NULL, NULL, CALLBACK_NULL);
if (mmresult == MMSYSERR_NOERROR)
{
__try
{
timeBeginPeriod(timePeriod);
__try
{
WAVEHDR hdr = {0};
hdr.dwBufferLength =
(ULONG)(nBuffer * sizeof(buffer[0]));
hdr.lpData = (LPSTR)&buffer[0];
mmresult = waveOutPrepareHeader(hWavOut,
&hdr, sizeof(hdr));
if (mmresult == MMSYSERR_NOERROR)
{
__try
{
ULONG start = GetTickCount();
mmresult =
waveOutWrite(hWavOut, &hdr, sizeof(hdr));
Sleep((ULONG)(1000 * nSeconds
- (GetTickCount() - start)));
}
__finally
{ waveOutUnprepareHeader(hWavOut, &hdr, sizeof(hdr)); }
}
}
__finally { timeEndPeriod(timePeriod); }
}
__finally { waveOutClose(hWavOut); }
}
}
__finally { free(buffer); }
return mmresult;
}
// Triangle wave generator
float triangle(float timeInSeconds, unsigned short channel, void *context)
{
const float frequency = *(const float *)context;
const float angle = (float)(frequency * 2 * M_PI * timeInSeconds);
switch (channel)
{
case 0: return (float)asin(sin(angle + 0 * M_PI/2));
default: return (float)asin(sin(angle + 1 * M_PI/2));
}
}
// Pure tone generator
float pure(float timeInSeconds, unsigned short channel, void *context)
{
const float frequency = *(const float *)context;
const float angle = (float)(frequency * 2 * M_PI * timeInSeconds);
switch (channel)
{
case 0: return (float)sin(angle + 0 * M_PI/2);
default: return (float)sin(angle + 1 * M_PI/2);
}
}
int _tmain(int argc, _TCHAR* argv[])
{
float frequency = 2 * 261.626F;
play(1, pure, &frequency);
return 0;
}
BOOL WINAPI Beep(
__in DWORD dwFreq,
__in DWORD dwDuration
);
經由PC揚聲器,或使用的DirectX音動作。 如果需要,我可以提供一些片段。
好蜂鳴功能沒有按不起作用,因爲它不能產生頻率組合。 DirectX的聲音看起來像是過度殺毒,因爲我只是想生成一個簡單的語氣...有沒有辦法用'waveOutWrite'這樣的東西來做?我認爲這是正確的方式,但我不知道要給它什麼數據。 – Mehrdad 2011-04-28 07:35:52
@Mehrdad:wavOutWrite預計WAV格式的聲音塊,iirc。 – 2011-04-29 05:20:35
@亞當:啊,現在*這是一個很好的答案。 =)隨意張貼,所以我可以接受它! (順便說一句,它是*完整*波形數據還是其中的一部分?我是否也需要發送所有RIFF標題?) – Mehrdad 2011-04-29 06:47:35
waveOut
功能處理聲音波形數據(如果我正確記得,以WAV格式)。
雖然這是針對WPF應用程序,以下鏈接應該證明對任何桌面應用程序有所幫助:
很酷,感謝您的鏈接! – Mehrdad 2011-04-29 18:00:45
+1。但我認爲三角波發生器是錯誤的。根據[Wikipedia](http://en.wikipedia.org/wiki/Triangle_wave#Definitions):'返回(float)asin(sin(angle + 0 * M_PI/2))* 2/M_PI;'。 – JRL 2015-03-01 18:10:28