0
$\begingroup$

I am working on C++ project based on Raspberry Pi. I have to make program that recognize siren of emergency vehicle(sound capture by microphone). I made a huge internet research and stopped with small issue.
I try to capture sound by Alsa and then put buffer into FFT to get main frequency of the surroundings. In parts everything works for me - FFT, sound capture. But I am stuck in getting things together.
I record sound to .pcm file and in the same time put it into array for further calculations. My FFT function working on this array gives back some random freqs which are possibly some noise. When I transform(with Audacity software) this .pcm (with samples from mic) into .wav and run FFT function I get correct freq.

I think there is possibilty that I made a mistake in transforming data from S16_LE into decimal samples because in sample logs from .pcm and .wav I see only differences. But as far as I know it is correctly normalized for wave file.
Or I have missed something alse.

For FFT I use lib: https://github.com/visore/QRealFourier
For Alsa I use -lasound

Below my code:
 int main (int argc, char *argv[])
    {
      int i;
      int err;
      char *buffer;
      int input;
      int buffer_frames = 128;
      unsigned int rate = 44100;
      snd_pcm_t *capture_handle;
      snd_pcm_hw_params_t *hw_params;
      snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
      int SIZE=(128 * snd_pcm_format_width(format) / 8 * 2);
      int SIZE2=65536;
      printf("capture_handle: %p\n", capture_handle);
      std::cout<<std::endl;
    
      if ((err = snd_pcm_open (&capture_handle, "default", SND_PCM_STREAM_CAPTURE, 0)) < 0) {
        fprintf (stderr, "cannot open audio device %s (%s)\n",
                 "default",
                 snd_strerror (err));
        exit (1);
      }
    
      fprintf(stdout, "audio interface opened\n");
    
      if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) {
        fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n",
                 snd_strerror (err));
        exit (1);
      }
    
      fprintf(stdout, "hw_params allocated\n");
    
      if ((err = snd_pcm_hw_params_any (capture_handle, hw_params)) < 0) {
        fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n",
                 snd_strerror (err));
        exit (1);
      }
    
      fprintf(stdout, "hw_params initialized\n");
    
      if ((err = snd_pcm_hw_params_set_access (capture_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
        fprintf (stderr, "cannot set access type (%s)\n",
                 snd_strerror (err));
        exit (1);
      }
    
      fprintf(stdout, "hw_params access setted\n");
    
      if ((err = snd_pcm_hw_params_set_format (capture_handle, hw_params, format)) < 0) {
        fprintf (stderr, "cannot set sample format (%s)\n",
                 snd_strerror (err));
        exit (1);
      }
    
      fprintf(stdout, "hw_params format setted\n");
    
      if ((err = snd_pcm_hw_params_set_rate_near (capture_handle, hw_params, &rate, 0)) < 0) {
        fprintf (stderr, "cannot set sample rate (%s)\n",
                 snd_strerror (err));
        exit (1);
      }
    
      fprintf(stdout, "hw_params rate setted\n");
    
      if ((err = snd_pcm_hw_params_set_channels (capture_handle, hw_params, 2)) < 0) {
        fprintf (stderr, "cannot set channel count (%s)\n",
                 snd_strerror (err));
        exit (1);
      }
    
      fprintf(stdout, "hw_params channels setted\n");
    
      if ((err = snd_pcm_hw_params (capture_handle, hw_params)) < 0) {
        fprintf (stderr, "cannot set parameters (%s)\n",
                 snd_strerror (err));
        exit (1);
      }
    
      fprintf(stdout, "hw_params setted\n");
    
      snd_pcm_hw_params_free (hw_params);
    
      fprintf(stdout, "hw_params freed\n");
    
      if ((err = snd_pcm_prepare (capture_handle)) < 0) {
        fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
                 snd_strerror (err));
        exit (1);
      }
    
      fprintf(stdout, "audio interface prepared\n");
        SIZE=(128 * snd_pcm_format_width(format) / 8 * 2);
      buffer = (char *)malloc(128 * snd_pcm_format_width(format) / 8 * 2);
    
      fprintf(stdout, "buffer allocated %d\n", snd_pcm_format_width(format) / 8 * 2);
        int fd = open("in21.pcm", O_CREAT | O_RDWR, 0666);
      //for (i = 0; i < 10; ++i) {
    
        //dodane
        float sample[SIZE2],fft[SIZE2];
    
        float x=0;
                   int licznik=0, 
      i = 0;
          while(i!=512){
          SIZE=(128 * snd_pcm_format_width(format) / 8 * 2);
        //snd_pcm_wait(capture_handle, 1000);
        if ((err = snd_pcm_readi (capture_handle, buffer, buffer_frames)) != buffer_frames) {
          fprintf (stderr, "read from audio interface failed (%s)\n",
                   snd_strerror (err));
          std::cout<<"fixed"<<std::endl;
         snd_pcm_prepare(capture_handle);
         // exit (1);
        }
        int b=0; //int a=i*128;
        for(int a=i*128;a<buffer_frames*(i+1);a++)
        { 
            int tmp=(int)buffer[b];
            std::cout<<std::dec<<tmp<<std::endl;
            std::cout<<tmp<<std::endl;
            sample[a]=tmp;
            b++;
            if(b>=128){
                b=0;
            }
        }
        write(fd, buffer, 128 * snd_pcm_format_width(format) / 8 * 2);
        fprintf(stdout, "read %d done\n", i);
        i++;
      }
      close(fd);
    
      free(buffer);
        std::cout<<"mic done"<<std::endl;
      fprintf(stdout, "buffer freed\n");
      float max=0;
      for(int c=0;c<SIZE2;c++)
      {
          if(max<=sample[c]) max=sample[c];
      }
      for(int c=0;c<SIZE2;c++)
      {
          if(sample[c]>127) sample[c]=sample[c]-max;
          sample[c]=sample[c]/32768;
      }

      QFourierTransformer transformer;
    
      //Setting a fixed size for the transformation
    
      if(transformer.setSize(SIZE2) == QFourierTransformer::VariableSize)
      {
    std::printf("This size is not a default fixed size of QRealFourier. Using a variable size instead.\n");
      }
      else if(transformer.setSize(SIZE2) == QFourierTransformer::InvalidSize)
      {
          std::cout<<"dupa"<<std::endl;
          return -1;
      }
      transformer.forwardTransform(sample, fft);
        std::cout<<"Samples after transformation and before rescaling:\n";
        std::ofstream dane("log.txt");
        for (int j=1;j<SIZE2/2;j++){

            dane<<"j: "<<j<<" "<<sample[j]<<std::endl;;

            if(x<=(sqrt(fft[j]*fft[j]+fft[j+SIZE2/2]*fft[j+SIZE2/2]))) {x=sqrt(fft[j]*fft[j]+fft[j+SIZE2/2]*fft[j+SIZE2/2]); licznik=j+1;} //re*re+im*im
        }
         std::cout<<"freq1: "<<(float)44100*licznik/SIZE2<<std::endl;
    
        dane.close();
      snd_pcm_close (capture_handle);
      fprintf(stdout, "audio interface closed\n");
    
      return 0;
    } 
$\endgroup$
1
  • 1
    $\begingroup$ why use that strange FFT library instead of FFTw / FFTS's real-valued transforms like everyone else? (and why on earth would one want to base one's math functions on Qt?!) $\endgroup$ – Marcus Müller Jan 3 at 20:46
0
$\begingroup$

This part is clearly wrong (but there might be other issues as well)

  float max=0;
  for(int c=0;c<SIZE2;c++)
  {
      if(max<=sample[c]) max=sample[c];
  }
  for(int c=0;c<SIZE2;c++)
  {
      if(sample[c]>127) sample[c]=sample[c]-max;
      sample[c]=sample[c]/32768;
  }

To convert samples stored in S16_LE format (which corresponds to 16 bit signed integer values) to float you just need to divide every sample by 32768 (which is the absolute maximum value that a sample can take). The range for the floating point values will now be -1 to +1 as it should be.

for(int c=0;c<SIZE2;c++)
{
 
  sample[c]=sample[c]/32768;
}

I assume that your buffer contains the correct sample values.

UPDATE:

Importing your file to Audacity shows that you don't have a distinct peak at any frequency (what exactly do you expect to see? ).

enter image description here

Your file is imported as 16 bit signed values sampled at 44100 Hz. Since pcm is a raw format (no header), you have to know the sampling rate as well as the bit depth (including whether the samples are stored as signed or unsigned values) to correctly interpret the values. Audacity, for example, supports only 16 bit signed values.

$\endgroup$
9
  • $\begingroup$ Thank you for response. I deleted the part with max value in buffer, but I still got the same. To check working I am playing 1kHz test signal. From this code I am getting ex. 356Hz or 21300Hz $\endgroup$ – Aerobird Jan 3 at 21:41
  • $\begingroup$ And the point is that, when I take this pcm file into wave and run the same FFT I get 999Hz. Values on buffer are not the same despite that they are taken from the same file. First sample pcm: 0.00778198; wav: -0.0062561. $\endgroup$ – Aerobird Jan 3 at 21:49
  • $\begingroup$ @Aerobird, post that file and I'll have a look tomorrow. $\endgroup$ – dsp_user Jan 3 at 21:59
  • $\begingroup$ Here: PCM File $\endgroup$ – Aerobird Jan 4 at 7:34
  • $\begingroup$ @Aerobird, updated my answer. $\endgroup$ – dsp_user Jan 4 at 9:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.