【问题标题】:waveInProc / Windows audio questionwaveInProc / Windows 音频问题
【发布时间】:2011-01-08 05:20:46
【问题描述】:

我正在使用 Windows API 来获取音频输入。我已经按照 MSDN 上的所有步骤,并设法将音频录制到 WAV 文件中。没问题。我正在使用多个缓冲区等等。我想对缓冲区做更多的事情,而不是简单地写入文件,所以现在我已经设置了一个回调。它工作得很好,我正在获取数据,但我不知道一旦我有了它该怎么做。

这是我的回调...这里一切正常:

// Media API callback
void CALLBACK AudioRecorder::waveInProc(HWAVEIN hWaveIn, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{

    // Data received
    if (uMsg == WIM_DATA)
    {

        // Get wav header
        LPWAVEHDR mBuffer = (WAVEHDR *)dwParam1;

        // Now what?
        for (unsigned i = 0; i != mBuffer->dwBytesRecorded; ++i)
        {

            // I can see the char, how do get them into my file and audio buffers?
            cout << mBuffer->lpData[i] << "\n";

        }

        // Re-use buffer
        mResultHnd = waveInAddBuffer(hWaveIn, mBuffer, sizeof(mInputBuffer[0])); // mInputBuffer is a const WAVEHDR *

    }

}

// waveInOpen cannot use an instance method as its callback, 
// so we create a static method which calls the instance version
void CALLBACK AudioRecorder::staticWaveInProc(HWAVEIN hWaveIn, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2)
{

    // Call instance version of method
    reinterpret_cast<AudioRecorder *>(dwParam1)->waveInProc(hWaveIn, uMsg, dwInstance, dwParam1, dwParam2);

}

就像我说的,效果很好,但我正在尝试执行以下操作:

  • 将数据转换为短格式并复制到数组中
  • 将数据转换为浮点数并复制到数组中
  • 将数据复制到一个更大的 char 数组中,我将其写入 WAV
  • 将数据中继到任意输出设备

我与 FMOD 合作过很多次,我对交错和所有这些都很熟悉。但是 FMOD 将所有内容都作为浮点数处理。在这种情况下,我会走另一条路。我想我基本上只是在寻找有关如何从 LPSTR 到 short、float 和 unsigned char 的资源。

非常感谢!

【问题讨论】:

  • 哇,谢谢大家的帮助!我知道这是一个非常笼统的问题,所以我很欣赏具体的答案。重新开始工作,很快就会标记答案/回复。
  • 请注意:wave API 非常挑剔 - 您不能在 wave 过程中做太多工作。 MSDN (msdn.microsoft.com/en-us/library/aa909756.aspx) 上的警告非常明确:从回调中调用 wave* 函数(如 waveInAddBuffer)极有可能死锁。

标签: c++ windows winapi audio


【解决方案1】:
typedef struct { 
    LPSTR      lpData; 
    // etc..
} WAVEHDR; 

嗯,尴尬的类型。它当然不是 STR,应该是 PVOID。只需将其转换为您需要的任何类型:

short* data = (short*)(mBuffer->lpData);
unsigned samples = mBuffer->dwBytesRecorded / sizeof(short);
// etc..

【讨论】:

  • 甜,这让我更了解这一点。
【解决方案2】:

我已经完成了所有这些,但信息太多,无法在此处详细解释。我建议你看一下source code of PortAudio:它是一个非常好的 MME 实现,虽然有些部分对我来说有点太乱了,但它包含了你所追求的一切,包括转换。

  • 转换数据:这取决于您的输入格式。 MME 缓冲区将所有内容存储在 char* 中,但这并不意味着实际样本是字符。它们可能是 8、16、24、32(int 或 float)或 64 位(float)。从一个整数到另一个不同大小的整数的转换通常使用简单的位移来完成。将整数转换为浮点数通常是首先使用简单的强制转换将整数转换为浮点数,然后将其除以该整数的最大值以获得介于 -1.0 和 1.0 之间的数字。这也称为标准化。您还可以为所有这些转换添加抖动。
  • 缓冲数据:您不想在回调中花费太多时间,否则会丢弃缓冲区,因此回调中的磁盘 I/O 未完成。 Imo 结合生产者/消费者模式的循环缓冲区最方便解决这个问题:缓冲区在 MME 回调中被填充(使用非常快的简单 memcpy),然后向另一个线程发出信号。收到信号后,线程检查缓冲区中有多少数据,如果足够则将其写入文件(您不想每次都将小块写入文件,而是等待大量数据并转储它立刻)。这样您就可以将慢速磁盘 I/O 与回调分开。
  • 获取数据到输出设备:就像你有一个waveInProc,你将有一个waveOutProc 用于输出。在该回调中,您应该将要输出的数据写入缓冲区。

【讨论】:

    【解决方案3】:

    将 8/16/32 位/样本数组转换为浮点数组:

    void src_BYTE_to_float_array(const unsigned char* in, float* out, int len)
    {
        while (len)
        {
            len--;
            out[len]= (float) (in [len] / (1.0 * 0x80) -1.0);
        }
    }
    
    void src_short_to_float_array(const short* in, float* out, int len)
    {
        while (len)
        {
            len--;
            out[len]= (float) (in [len] / (1.0 * 0x8000)) ;
        }
    }
    
    void src_int_to_float_array(const int* in, float* out, int len)
    {
        while (len)
        {
            len--;
            out[len]= (float) (in [len] / (8.0 * 0x10000000)) ;
        }
    }
    

    要播放样本,您必须执行相反的操作:

    void src_float_to_BYTE_array(const float* in, unsigned char* out, int len)
    {
        double scaled_value;
    
        while (len)
        {
            len--;
    
            scaled_value= in[len] * (8.0 * 0x10000000);
            if (scaled_value >= (1.0 * 0x7FFFFFFF))
            {
                out[len]= 255;
                continue ;
            }
    
            out[len]= (unsigned char)((lrint(scaled_value) >> 24) + 0x80);
        }
    }
    
    void src_float_to_short_array(const float* in, short* out, int len)
    {   
        double scaled_value;
    
        while (len)
        {
            len--;
    
            scaled_value= in[len] * (8.0 * 0x10000000);
            if (scaled_value >= (1.0 * 0x7FFFFFFF))
            {
                out[len]= 32767;
                continue ;
            }
    
            out[len]= (short)(lrint(scaled_value) >> 16);
        }
    }
    
    void src_float_to_int_array(const float* in, int* out, int len)
    {   
        double scaled_value;
    
        while (len)
        {
            len--;
    
            scaled_value= in[len] * (8.0 * 0x10000000);
            if (scaled_value >= (1.0 * 0x7FFFFFFF))
            {
                out[len]= 0x7fffffff;
                continue;
            }
    
            out[len]= lrint(scaled_value);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-08
      相关资源
      最近更新 更多