1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

multitone sine wave frequencies

Discussion in 'C' started by ogopa, Aug 17, 2011.

  1. ogopa

    ogopa New Member

    Joined:
    Aug 16, 2011
    Messages:
    7
    Likes Received:
    1
    Trophy Points:
    0
    I have a program that generates a sine wave. I wanted to know how to generate a multitone wave with 2 frequencies using this program.What has to be changed? Any help would be greatly appreciated.

    Code:
    static void generate_sine(const snd_pcm_channel_area_t *areas, 
                               snd_pcm_uframes_t offset,
                               int count, double *_phase)
     {
             static double max_phase = 2. * M_PI;
             double phase = *_phase;
             double step = max_phase*freq/(double)rate;
             unsigned char *samples[channels];
             int steps[channels];
             unsigned int chn;
             int format_bits = snd_pcm_format_width(format);
             unsigned int maxval = (1 << (format_bits - 1)) - 1;
             int bps = format_bits / 8;  // bytes per sample 
             int phys_bps = snd_pcm_format_physical_width(format) / 8;
             int big_endian = snd_pcm_format_big_endian(format) == 1;
             int to_unsigned = snd_pcm_format_unsigned(format) == 1;
             int is_float = (format == SND_PCM_FORMAT_FLOAT_LE ||
                             format == SND_PCM_FORMAT_FLOAT_BE);
         float amplitude_scale = amplitude/8.56;
         
        
         // verify and prepare the contents of areas 
             for (chn = 0; chn < channels; chn++) {
                     if ((areas[chn].first % 8) != 0) {
                             printf("areas[%i].first == %i, aborting...", chn , areas[chn].first);
                             exit(EXIT_FAILURE);
                     }
                     samples[chn] = (((unsigned char *)areas[chn].addr) + (areas[chn].first / 8));
                    if ((areas[chn].step % 16) != 0) {
                            // printf("areas[%i].step == %i, aborting...  ", chn areas[chn].step);
                            exit(EXIT_FAILURE);
                     }
                     steps[chn] = areas[chn].step / 8;
                     samples[chn] += offset * steps[chn];
             }
             // fill the channel areas 
             while (count-- > 0) {
                     union {
                             float f;
                             int i;
                     } fval;
                     int res, i;
                     if (is_float) {
                             fval.f = amplitude_scale * sin(phase) * maxval;
                             res = fval.i;
                     } else
                             res = amplitude_scale * sin(phase) * maxval;
                     if (to_unsigned)
                             res ^= 1U << (format_bits - 1);
                     for (chn = 0; chn < channels; chn++) {
                             // Generate data in native endian format 
                             if (big_endian) {
                                     for (i = 0; i < bps; i++)
                                             *(samples[chn] + phys_bps - 1 - i) = (res >> i * 8) & 0xff;
                             } else {
                              //       for (i = 0; i < bps; i++)
                             //                *(samples[chn] + i) = (res >>  i * 8) & 0xff;
                             }
                             samples[chn] += steps[chn];
                     }
                     phase += step;
                     if (phase >= max_phase)
                             phase -= max_phase;
             }
             *_phase = phase;
     }
    Code:
    static int write_loop(snd_pcm_t *handle,
                           signed short *samples,
                           snd_pcm_channel_area_t *areas)
     {
             double phase = 0;
             signed short *ptr;
             int err, cptr;
     
             while (1) {
                     generate_sine(areas, 0, period_size, &phase);
             ptr = samples;
                     cptr = period_size;
                     while (cptr > 0) {
                             err = snd_pcm_writei(handle, ptr, cptr);
                             if (err == -EAGAIN)
                                     continue;
                             if (err < 0) {
                                     if (xrun_recovery(handle, err) < 0) {
                                             printf("Write error: %s  ", snd_strerror(err));
                                             exit(EXIT_FAILURE);
                                     }
                                     break;  /* skip one period */
                             }
                             ptr += err * channels;
                             cptr -= err;
                     }
             }
     }
    Code:
    
    



    Code:
    int main(int argc, char *argv[])
     {
             snd_pcm_t *handle;
             int err;
             snd_pcm_hw_params_t *hwparams;
             snd_pcm_sw_params_t *swparams;
             int method = 0;
             signed short *samples;
             unsigned int chn;
             snd_pcm_channel_area_t *areas;
     
              snd_pcm_hw_params_alloca(&hwparams);
        snd_pcm_sw_params_alloca(&swparams);
    
        err = snd_output_stdio_attach(&output, stdout, 0);
        printf( "snd_output_stdio_attach err=%d\n", err);
        err = snd_pcm_open(&hspdif, device, SND_PCM_STREAM_PLAYBACK, 0);
        printf( "snd_pcm_open err=%d\n", err);
        err = set_hwparams(hspdif, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED);
        printf( "set_hwparams err=%d\n", err);
        err = set_swparams(hspdif, swparams);
        printf( "set_swparams err=%d\n", err);
    
        samples = new signed short [period_size * channels * snd_pcm_format_physical_width(format)];
        printf( "samples array_size=%d\n", int( period_size * channels * snd_pcm_format_physical_width(format)) );
    
        areas = new snd_pcm_channel_area_t [channels];
        printf( "areas channels=%d\n", channels);
        for (unsigned int chn = 0; chn < channels; chn++) {
                areas[chn].addr = samples;
                areas[chn].first = chn * snd_pcm_format_physical_width(format);
                areas[chn].step = channels * snd_pcm_format_physical_width(format);
        }
     
             err = transfer_methods[method].transfer_loop(handle, samples, areas);
             if (err < 0)
                     printf("Transfer failed: %s", snd_strerror(err));
    
             delete [] areas;
             delete []samples;
             snd_pcm_close(handle);
             return 0;
     }
     
  2. xpi0t0s

    xpi0t0s Mentor

    Joined:
    Aug 6, 2004
    Messages:
    3,012
    Likes Received:
    203
    Trophy Points:
    0
    Occupation:
    Senior Support Engineer
    Location:
    England
    If I read the code correctly then the line where you calculate the data point is this:
    Code:
    res = amplitude_scale * sin(phase) * maxval;
    
    So it's just a case of doubling up on this, bearing in mind that you may need to reduce the maxval to prevent clipping when peaks reinforce:
    Code:
    res = (amplitude_scale1 * sin(phase1) + amplitude_scale2 * sin(phase2)) * maxval/2;
    
     
  3. ogopa

    ogopa New Member

    Joined:
    Aug 16, 2011
    Messages:
    7
    Likes Received:
    1
    Trophy Points:
    0

    Thanks alot. That worked perfectly.
     

Share This Page