multitone sine wave frequencies

ogopa's Avatar, Join Date: Aug 2011
Light Poster
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:
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;
 }
xpi0t0s's Avatar, Join Date: Aug 2004
Mentor
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;
ogopa like this
ogopa's Avatar, Join Date: Aug 2011
Light Poster
Quote:
Originally Posted by xpi0t0s View Post
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;

Thanks alot. That worked perfectly.