簡體   English   中英

alsa linux c 程序輸出上的奇怪正弦波

[英]Strange sine wave on output of an alsa linux c program

我正在 ubuntu 上學習 alsa 編程。

我正在嘗試將正弦波輸出到我的筆記本電腦聲卡的線路輸出,然后通過音頻電纜重定向到線路輸入(麥克風)。

  ___LINE_IN(microphone)\
 /                       \
|                         \ _____________
|                          |soundcard-pc |
cable                     /
|                        /
 \ ___LINE_OUT(speakers)/

我正在使用此代碼

#include<stdio.h>
#include<stdlib.h>
#include<alsa/asoundlib.h>
#include<math.h>

#define SIZEBUF 2048

int main(void)
{
    int i;
    int err;
    double x;
    double cost;
    double frequency=500;
    unsigned int rate=44100;
    short buf[SIZEBUF];
    snd_pcm_t *phandle;
    snd_pcm_hw_params_t *hw_params;

    snd_pcm_open(&phandle, "default", SND_PCM_STREAM_PLAYBACK, 0);
    snd_pcm_hw_params_malloc(&hw_params);
    snd_pcm_hw_params_any(phandle, hw_params);

    if ((err = snd_pcm_hw_params_set_access(phandle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
        printf("Cannot set access type.\n");
        exit(1);
    }
    snd_pcm_hw_params_set_format(phandle, hw_params, SND_PCM_FORMAT_S16_LE);
    snd_pcm_hw_params_set_rate_near(phandle, hw_params, &rate, 0);
    snd_pcm_hw_params_set_channels(phandle, hw_params, 1);
    snd_pcm_hw_params(phandle, hw_params);
    snd_pcm_hw_params_free(hw_params);
    snd_pcm_prepare(phandle);

    cost = 2.0 * M_PI * frequency / (double)rate;

    printf("cost=%f.\n", cost);
    for (i = 1 ; i < SIZEBUF ; i++) {
        x      = sin(i * cost);
        buf[i] = (short)(32767 * x + 32768);
    }

    for (i = 0 ; i < 50 ; i++) {
        snd_pcm_writei(phandle, buf, SIZEBUF);
    }
    snd_pcm_close(phandle);

    exit(0);
}

我正在使用大膽來查看波浪,但它看起來很奇怪,就像在這張圖片中一樣

在此處輸入圖片說明

它似乎沒有正弦波的行為。 為什么?

您正在使用類型為short樣本,並且已將它們正確聲明為S16_LE 但是,您的代碼隨后會像未簽名一樣計算這些值:

buf[i] = (short)(32767 * x + 32768);

您不需要偏移量; 對於帶符號的樣本,零實際上是零。 用這個:

buf[i] = (short)(32767 * x);

要將浮點樣本轉換為 SND_PCM_FORMAT_S16_LE,請執行以下操作:

#include <endian.h>
#include <math.h>
#include <stdint.h>

// assume -1.0 <= x <= 1.0                                                      
int16_t float_to_s16le (float x)
{
    int16_t s16 = trunc (x * 32767); // rounds toward zero                      
    return htole16 (s16);
}

一些備注:

  • 您正在轉換為有符號數,而不是無符號數。 此外,避免剪切或環繞大值也很重要。
  • 您需要一種具有特定位數的類型。 因此使用 int16_t,而不是短。
  • 通常您會選擇主機字節序 (SND_PCM_FORMAT_S16)。 但是由於您明確選擇了 Little Endian,因此您需要確保這是您生成的(使用htole16或等效項)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM