且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

多音调使用portaudio到声卡

更新时间:2022-10-15 15:19:17

PortAudio有样品code产生的音调,你只需要弄清楚的频率。例如,见这样的回答:

[portaudio]Transmit和检测频率 - 视窗

更新:

而不是试图存储正弦数据的表,简单地在回调使用该公式计算出的正弦值:

振幅[N] = SIN(N * desiredFreq * 2 * PI /采样率)

这样(未经测试)的code会是这个样子:

  typedef结构
{
    N久;
}迈德特;浮动频率= 422;静态INT myCallBack函数(
                    常量无效* INPUTBUFFER,
                    无效* OutputBuffer中,
                    无符号长framesPerBuffer,
                    常量PaStreamCallbackTimeInfo * timeInfo,
                    PaStreamCallbackFlags statusFlags,
                    void *的用户数据
                  )
{
    迈德特*数据=(迈德特*)用户数据;
    浮*总分=(浮点*)OutputBuffer中;    (无效)timeInfo; / * prevent未使用变量警告。 * /
    (无效)statusFlags;
    (无效)INPUTBUFFER;    为(无符号​​长I = 0; I< framesPerBuffer;我++)
    {
        //填充输出缓冲区正弦波
        浮动V =罪(数据并行将N *频率* 2 * PI /(浮点)SAMPLERATE)
        *总分++ = V; // 剩下
        *总分++ = V; // 对
    }    返回paContinue;
}

这code是不是没有问题:例如。最终将n环绕,我不知道,如果罪还在准确,高效的输入变大。尽管如此,它是一个很好的起点,如果你只需要生成在现代硬件上的声音的几秒钟,这真的是你所需要的。如果你需要的东西票友,得到这第一个工作日,那么你可以不用担心使其更加高效,稳定与LUT。

I am trying to generate a tone to the sound card (Frequency: 1950 hz, duration: 40 ms, level: -30 db, right-channel (stereo), on steam 1). Eventually, I would like to play two of these tones (one goes to channel 1 and one goes to channel 2).

Any help or direction is greatly appreciated.

Thanks, DW


Hi Bjorn, I tried this but I am not getting the what I am expecting as a frequency (plus seems sound is not clean). Any ideas what's wrong? I greatly appreciate any help.

#define SAMPLE_RATE   (44100)
#define TABLE_SIZE   (200)
float FREQUENCY = 422;

...
for(int i=0; i<TABLE_SIZE; i++ )
{
    data.sine[i] = (float) sin( (double)i * ((2.0 * M_PI)/(double)SAMPLE_RATE) * FREQUENCY );
}

data.left_phase = 0;
data.right_phase = 0;
...

... in callback function ...
for(unsigned long i = 0; i < framesPerBuffer; i++ )
{   

  // fill output buffer with sin wave
  *out++ = data->amp * data->sine[data->left_phase];  // left     
  *out++ = data->amp * data->sine[data->right_phase]; // right                  

  data->left_phase += 1;    

  if( data->left_phase >= TABLE_SIZE ) 
    data->left_phase -= TABLE_SIZE;           

  data->right_phase += 1; 

  if( data->right_phase >= TABLE_SIZE ) 
    data->right_phase -= TABLE_SIZE;
} 

PortAudio has sample code for generating tones, you just need to figure out the frequency. See for example this answer:

[portaudio]Transmit and Detect frequency - Windows

Update:

Rather than trying to store a table of sine data, simply calculate the sine value in the callback using this formula:

amplitude[n] = sin( n * desiredFreq * 2 * pi / samplerate )

so (untested) your code will look something like this:

typedef struct
{
    long n;
} MyData;

float FREQUENCY = 422;

static int MyCallback(  
                    const void *inputBuffer, 
                    void *outputBuffer,
                    unsigned long framesPerBuffer,
                    const PaStreamCallbackTimeInfo* timeInfo,
                    PaStreamCallbackFlags statusFlags,
                    void *userData 
                  )
{   
    MyData *data = (MyData*)userData;
    float *out = (float*)outputBuffer;    

    (void) timeInfo; /* Prevent unused variable warnings. */
    (void) statusFlags;
    (void) inputBuffer;     

    for(unsigned long i = 0; i < framesPerBuffer; i++ )
    {               
        // fill output buffer with sin wave
        float v = sin( data->n * FREQUENCY * 2 * PI / (float) SAMPLERATE )
        *out++ = v; // left         
        *out++ = v; // right
    }   

    return paContinue;
}

This code is not without problems: eg. eventually n will "wrap around" and I'm not sure if sin remains accurate and efficient as the input gets larger. Nevertheless it's a good starting point, and if you just need to generate a few seconds of a tone on modern hardware, this is really all you need. If you need something fancier, get this working first, then you can worry about making it more efficient and robust with a LUT.