【问题标题】:Playing an arbitrary sound on Windows?在 Windows 上播放任意声音?
【发布时间】:2011-04-28 07:01:51
【问题描述】:

例如,我如何在 Windows(32 位和 64 位,直到 Windows 7)本机上播放具有给定幅度和给定频率构成(例如,由频率 2 kHz 和 3 kHz 组成)的声音?

(本机我的意思是不使用外部库。)

我认为这需要waveOutWrite 方法,但我不知道它是如何工作的。

【问题讨论】:

    标签: winapi audio wave


    【解决方案1】:

    我得到了一些工作......

    #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;
    }
    

    【讨论】:

    • +1。但我认为三角波发生器是错误的。根据Wikipedia:return (float)asin(sin(angle + 0 * M_PI / 2)) * 2 / M_PI;.
    【解决方案2】:

    Beep

    BOOL WINAPI Beep(
        __in  DWORD dwFreq,
        __in  DWORD dwDuration
    );
    

    【讨论】:

      【解决方案3】:

      waveOut 函数处理声音波形数据(如果我没记错的话,是 WAV 格式)。

      虽然这是针对 WPF 应用程序,但以下链接应该对任何桌面应用程序都有帮助:

      Sound Generation in WPF Applications

      【讨论】:

        【解决方案4】:

        通过 PC 扬声器或使用 Directx Sound 发出哔声。 如果您需要,我可以提供一些 sn-ps。

        【讨论】:

        • Beep 功能不起作用,因为它无法生成频率组合。 DirectX 的声音似乎有点矫枉过正,因为我只想生成一个简单的音调……有没有办法用waveOutWrite 之类的东西来做到这一点?我认为这是正确的方法,但我不知道该提供什么数据。
        • @Mehrdad:wavOutWrite 需要 WAV 格式的声音块,iirc。
        • @Adam:啊,现在是一个很好的答案。 =)请随意张贴,以便我接受! (顺便说一句,它是 完整 波形数据还是只是其中的一部分?我是否也需要发送所有 RIFF 标头?)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-22
        相关资源
        最近更新 更多