0

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;
} 
David W.
  • 23
  • 1
  • 1
  • 6

1 Answers1

1

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.

Community
  • 1
  • 1
Bjorn Roche
  • 11,279
  • 6
  • 36
  • 58
  • 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. Please see code above. – David W. Sep 28 '12 at 13:25
  • 1
    I think you are getting confused by using the table. The table is just there for optimization. Why not start by simply generating the tone in the callback using the sin function? – Bjorn Roche Sep 28 '12 at 17:03
  • Bjorn, that was the problem I was mixing the data table, which an optimization, and getting the right data in the callback. Your suggestion to work directly in the callback does the trick. Thanks again. BTW I didn't see your response prior to my other posting. David. – David W. Sep 28 '12 at 18:52
  • glad it worked out! Maybe you could mark my answer as correct wink wink nudge nudge :) – Bjorn Roche Sep 29 '12 at 04:07