【问题标题】:Unclear sound or high pitched noise when recording with ALSA on NanoPi NEO在 NanoPi NEO 上使用 ALSA 录音时声音不清晰或尖锐噪音
【发布时间】:2022-12-21 22:11:58
【问题描述】:

我正在努力处理可以在Linuxjournal 中找到的 ALSA 示例

我将代码复制到 .c 文件中并将它们 gcc -Wall Record_Listing4.c -lasound -o record 编译成可执行文件: Listing3 为play,Listing4 为record

我正在使用 Nanopi NEOUGO soundcard

我确保将默认音频设备指向提到的 USB 声卡。

我可以使用这个考试录制声音甚至听它,但有一个问题: 如果我按原样吹奏./record | ./play,我会得到非常响亮和高音调的噪音作为背景。

我发现我的耳机需要 2 个香奈儿立体声,而我的麦克风需要 1 个香奈儿单声道。所以我试图将这个单声道与自身交错以创建立体声。

这带来了一些成功,因为我设法消除了高音调噪音,但现在我的声音中出现了某种静态噪音。

这是我第一次尝试直接使用声音创建应用程序,所以我试图理解为什么我会听到噪音。 arecord 工作正常并且记录没有问题,所以它不是硬件。

修改后的代码如下

回放_Listing3

/*

This example reads standard from input and writes
to the default PCM device for 5 seconds of data.

*/

/* Use the newer ALSA API */
#define ALSA_PCM_NEW_HW_PARAMS_API

#include <alsa/asoundlib.h>

int main() {
  long loops;
  int rc;
  int size;
  snd_pcm_t *handle;
  snd_pcm_hw_params_t *params;
  unsigned int val;
  int dir;
  snd_pcm_uframes_t frames;
  char *buffer;

  /* Open PCM device for playback. */
  rc = snd_pcm_open(&handle, "default",
                    SND_PCM_STREAM_PLAYBACK, 0);
  if (rc < 0) {
    fprintf(stderr,
            "unable to open pcm device: %s\n",
            snd_strerror(rc));
    exit(1);
  }

  /* Allocate a hardware parameters object. */
  snd_pcm_hw_params_alloca(&params);

  /* Fill it in with default values. */
  snd_pcm_hw_params_any(handle, params);

  /* Set the desired hardware parameters. */

  /* Interleaved mode */
  snd_pcm_hw_params_set_access(handle, params,
                      SND_PCM_ACCESS_RW_INTERLEAVED);

  /* Signed 16-bit little-endian format */
  snd_pcm_hw_params_set_format(handle, params,
                              SND_PCM_FORMAT_S16_LE);

  /* Two channels (stereo) */
  snd_pcm_hw_params_set_channels(handle, params, 2);

  /* 44100 bits/second sampling rate (CD quality) */
  val = 44100;
  snd_pcm_hw_params_set_rate_near(handle, params,
                                  &val, &dir);

  /* Set period size to 32 frames. */
  frames = 32;
  snd_pcm_hw_params_set_period_size_near(handle,
                              params, &frames, &dir);

  /* Write the parameters to the driver */
  rc = snd_pcm_hw_params(handle, params);
  if (rc < 0) {
    fprintf(stderr,
            "unable to set hw parameters: %s\n",
            snd_strerror(rc));
    exit(1);
  }

  /* Use a buffer large enough to hold one period */
  snd_pcm_hw_params_get_period_size(params, &frames,
                                    &dir);
  size = frames * 4; /* 2 bytes/sample, 2 channels */
  buffer = (char *) malloc(size);

  /* We want to loop for 5 seconds */
  snd_pcm_hw_params_get_period_time(params,
                                    &val, &dir);
  /* 5 seconds in microseconds divided by
   * period time */
  loops = 5000000 / val;

  while (loops > 0) {
    loops--;
    rc = read(0, buffer, size);
    if (rc == 0) {
      fprintf(stderr, "end of file on input\n");
      break;
    } else if (rc != size) {
      fprintf(stderr,
              "short read: read %d bytes\n", rc);
    }
    rc = snd_pcm_writei(handle, buffer, frames);
    if (rc == -EPIPE) {
      /* EPIPE means underrun */
      fprintf(stderr, "underrun occurred\n");
      snd_pcm_prepare(handle);
    } else if (rc < 0) {
      fprintf(stderr,
              "error from writei: %s\n",
              snd_strerror(rc));
    }  else if (rc != (int)frames) {
      fprintf(stderr,
              "short write, write %d frames\n", rc);
    }
  }

  snd_pcm_drain(handle);
  snd_pcm_close(handle);
  free(buffer);

  return 0;
}

记录清单4

/*

This example reads from the default PCM device
and writes to standard output for 5 seconds of data.

*/

/* Use the newer ALSA API */
#define ALSA_PCM_NEW_HW_PARAMS_API

#include <alsa/asoundlib.h>

void interleave(const char * in_L,     // mono input buffer (left channel)
                const char * in_R,     // mono input buffer (right channel)
                char * out,            // stereo output buffer
                const size_t num_samples)  // number of samples
{
    for (size_t i = 0; i < num_samples; ++i)
    {
        out[i * 4] = in_L[i];
        out[i * 4 + 1] = in_L[i+1];
        out[i * 4 + 2] = 0;
        out[i * 4 + 3] = 0;
    }
}

int main() {
  long loops;
  int rc;
  int size;
  snd_pcm_t *handle;
  snd_pcm_hw_params_t *params;
  unsigned int val;
  int dir;
  snd_pcm_uframes_t frames;
  char *buffer;
  char *stereo;

  /* Open PCM device for recording (capture). */
  rc = snd_pcm_open(&handle, "default",
                    SND_PCM_STREAM_CAPTURE, 0);
  if (rc < 0) {
    fprintf(stderr,
            "unable to open pcm device: %s\n",
            snd_strerror(rc));
    exit(1);
  }

  /* Allocate a hardware parameters object. */
  snd_pcm_hw_params_alloca(&params);

  /* Fill it in with default values. */
  snd_pcm_hw_params_any(handle, params);

  /* Set the desired hardware parameters. */

  /* Interleaved mode */
  snd_pcm_hw_params_set_access(handle, params,
                      SND_PCM_ACCESS_RW_INTERLEAVED);

  /* Signed 16-bit little-endian format */
  snd_pcm_hw_params_set_format(handle, params,
                              SND_PCM_FORMAT_S16_LE);

  /* Two channels (stereo) */
  snd_pcm_hw_params_set_channels(handle, params, 1);

  /* 44100 bits/second sampling rate (CD quality) */
  val = 44100;
  snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);

  /* Set period size to 32 frames. */
  frames = 32;
  snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);

  /* Write the parameters to the driver */
  rc = snd_pcm_hw_params(handle, params);
  if (rc < 0) {
    fprintf(stderr,
            "unable to set hw parameters: %s\n",
            snd_strerror(rc));
    exit(1);
  }

  /* Use a buffer large enough to hold one period */
  snd_pcm_hw_params_get_period_size(params,
                                      &frames, &dir);
  size = frames * 2; /* 2 bytes/sample, 2 channels */
  buffer = (char *) malloc(size);
  stereo = (char *) malloc(size*2);

  /* We want to loop for 5 seconds */
  snd_pcm_hw_params_get_period_time(params,
                                         &val, &dir);
  loops = 5000000 / val;

  while (loops > 0) {
    loops--;
    rc = snd_pcm_readi(handle, buffer, frames);
    if (rc == -EPIPE) {
      /* EPIPE means overrun */
      fprintf(stderr, "overrun occurred\n");
      snd_pcm_prepare(handle);
    } else if (rc < 0) {
      fprintf(stderr,
              "error from read: %s\n",
              snd_strerror(rc));
    } else if (rc != (int)frames) {
      fprintf(stderr, "short read, read %d frames\n", rc);
    }
    interleave(buffer, buffer, stereo, frames);
    rc = write(1, stereo, size*2);
    if (rc != size*2)
      fprintf(stderr,
              "short write: wrote %d bytes\n", rc);
  }

  snd_pcm_drain(handle);
  snd_pcm_close(handle);
  free(buffer);

  return 0;
}

【问题讨论】:

    标签: c ubuntu audio alsa


    【解决方案1】:

    更新

    我已经设法解决了这个问题。潜在的原因是记录格式和回报格式之间的不一致。我需要正确地从麦克风中插入单声道以创建没有噪音或静电的适当立体声。我在下面为任何挣扎的人发布代码。

    记录

    /*
    
    This example reads from the default PCM device
    and writes to standard output for 5 seconds of data.
    
    */
    
    /* Use the newer ALSA API */
    #define ALSA_PCM_NEW_HW_PARAMS_API
    
    #include <alsa/asoundlib.h>
    
    void interleave(const uint16_t * in_L,     // mono input buffer (left channel)
                    const uint16_t * in_R,     // mono input buffer (right channel)
                    uint16_t * out,            // stereo output buffer
                    const size_t num_samples)  // number of samples 
    {
        for (size_t i = 0; i < num_samples; ++i)
        {
            out[i*2] = in_L[i];
            out[i*2+1] = in_R[i];
        }
    }
    
    int main() {
      long loops;
      int rc;
      int size;
      snd_pcm_t *handle;
      snd_pcm_hw_params_t *params;
      unsigned int val;
      int dir;
      snd_pcm_uframes_t frames;
      char *buffer;
      char *stereo;
      snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
      int channels = 2;
    
      /* Open PCM device for recording (capture). */
      rc = snd_pcm_open(&handle, "default",
                        SND_PCM_STREAM_CAPTURE, 0);
      if (rc < 0) {
        fprintf(stderr,
                "unable to open pcm device: %s
    ",
                snd_strerror(rc));
        exit(1);
      }
    
      /* Allocate a hardware parameters object. */
      snd_pcm_hw_params_alloca(&params);
    
      /* Fill it in with default values. */
      snd_pcm_hw_params_any(handle, params);
    
      /* Set the desired hardware parameters. */
    
      /* Interleaved mode */
      snd_pcm_hw_params_set_access(handle, params,
                          SND_PCM_ACCESS_RW_INTERLEAVED);
    
      /* Signed 16-bit little-endian format */
      snd_pcm_hw_params_set_format(handle, params, format);
    
      /* Two channels (stereo) */
      snd_pcm_hw_params_set_channels(handle, params, channels);
    
      /* 44100 bits/second sampling rate (CD quality) */
      val = 44100;
      snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
    
      /* Set period size to 32 frames. */
      frames = 128;
      snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
    
      /* Write the parameters to the driver */
      rc = snd_pcm_hw_params(handle, params);
      if (rc < 0) {
        fprintf(stderr,
                "unable to set hw parameters: %s
    ",
                snd_strerror(rc));
        exit(1);
      }
    
      /* Use a buffer large enough to hold one period */
      snd_pcm_hw_params_get_period_size(params, &frames, &dir);
      int width = (snd_pcm_format_width(format)/8);
      fprintf(stderr,"Format width: %d
    ", width);
      size = frames * width; /* 2 bytes/sample, 2 channels */
      buffer = (char *) malloc(size);
      stereo = (char *) malloc(size*2);
    
      for(int i = 0; i < 2*size; i++){
        stereo[i] = 0x00;
      }
    
      /* We want to loop for 5 seconds */
      snd_pcm_hw_params_get_period_time(params, &val, &dir);
      loops = 5000000 / val;
    
      while (loops > 0) {
        loops--;
        rc = snd_pcm_readi(handle, buffer, frames);
        if (rc == -EPIPE) {
          /* EPIPE means overrun */
          fprintf(stderr, "overrun occurred
    ");
          snd_pcm_prepare(handle);
        } else if (rc < 0) {
          fprintf(stderr,
                  "error from read: %s
    ",
                  snd_strerror(rc));
        } else if (rc != (int)frames) {
          fprintf(stderr, "short read, read %d frames
    ", rc);
        }
        if(channels > 1){
            interleave((uint16_t*)buffer,(uint16_t*)buffer,(uint16_t*)stereo,frames);
            write(1, stereo, 2*size);
        }
        else{
            write(1, buffer, size);
        }
      }
    
      snd_pcm_drain(handle);
      snd_pcm_close(handle);
      free(buffer);
    
      return 0;
    }
    

    回放

    /*
    
    This example reads standard from input and writes
    to the default PCM device for 5 seconds of data.
    
    */
    
    /* Use the newer ALSA API */
    #define ALSA_PCM_NEW_HW_PARAMS_API
    
    #include <alsa/asoundlib.h>
    
    int main() {
      long loops;
      int rc;
      int size;
      snd_pcm_t *handle;
      snd_pcm_hw_params_t *params;
      unsigned int rate = 44100;
      int dir;
      snd_pcm_uframes_t frames;
      char *buffer;
      char* stereo;
      snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
      int channels = 2;
    
      /* Open PCM device for playback. */
      rc = snd_pcm_open(&handle, "default",
                        SND_PCM_STREAM_PLAYBACK, 0);
      if (rc < 0) {
        fprintf(stderr,
                "unable to open pcm device: %s
    ",
                snd_strerror(rc));
        exit(1);
      }
    
      /* Allocate a hardware parameters object. */
      snd_pcm_hw_params_alloca(&params);
    
      /* Fill it in with default values. */
      snd_pcm_hw_params_any(handle, params);
    
      /* Set the desired hardware parameters. */
    
      /* Interleaved mode */
      snd_pcm_hw_params_set_access(handle, params,
                          SND_PCM_ACCESS_RW_INTERLEAVED);
    
      /* Signed 16-bit little-endian format */
      snd_pcm_hw_params_set_format(handle, params, format);
    
      /* Two channels (stereo) */
      snd_pcm_hw_params_set_channels(handle, params, channels);
    
      /* 44100 bits/second sampling rate (CD quality) */;
      rc = snd_pcm_hw_params_set_rate_near(handle, params, &rate, &dir);
      if(rc < 0){
        unsigned int r;
        snd_pcm_hw_params_get_rate(params, &r, &dir);
        fprintf(stderr, "cannot set sample rate, using: %d
    ", r);
      }
    
      /* Set period size to 32 frames. */
      frames = 128;
      snd_pcm_hw_params_set_period_size_near(handle,
                                  params, &frames, &dir);
    
      /* Write the parameters to the driver */
      rc = snd_pcm_hw_params(handle, params);
      if (rc < 0) {
        fprintf(stderr,
                "unable to set hw parameters: %s
    ",
                snd_strerror(rc));
        exit(1);
      }
    
      /* Use a buffer large enough to hold one period */
      snd_pcm_hw_params_get_period_size(params, &frames,
                                        &dir);
      size = frames * (snd_pcm_format_width(format)/8) * channels; /* 2 bytes/sample, 2 channels */
      buffer = (char *) malloc(size);
      stereo = malloc(2*size);
      /* We want to loop for 5 seconds */
      snd_pcm_hw_params_get_period_time(params, &rate, &dir);
      /* 5 seconds in microseconds divided by
       * period time */
      loops = 5000000 / rate;
    
      while (loops > 0) {
        loops--;
        rc = read(0, buffer, size);
        if (rc == 0) {
          fprintf(stderr, "end of file on input
    ");
          break;
        } else if (rc != size) {
          fprintf(stderr,
                  "short read: read %d bytes
    ", rc);
        }
        rc = snd_pcm_writei(handle, buffer, frames);
        if (rc == -EPIPE) {
          /* EPIPE means underrun */
          fprintf(stderr, "underrun occurred
    ");
          snd_pcm_prepare(handle);
        } else if (rc < 0) {
          fprintf(stderr,
                  "error from writei: %s
    ",
                  snd_strerror(rc));
        }  else if (rc != (int)frames) {
          fprintf(stderr,
                  "short write, write %d frames
    ", rc);
        }
      }
    
      snd_pcm_drain(handle);
      snd_pcm_close(handle);
      free(buffer);
    
      return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-05-05
      • 2012-05-19
      • 1970-01-01
      • 2020-08-11
      • 1970-01-01
      • 1970-01-01
      • 2015-07-24
      相关资源
      最近更新 更多