LINUX.ORG.RU

Программирование, ALSA


0

1

всем привет! Недавно захотел написать свой гитарный тюнер, для чего решил использовать Alsa. но уже с первых шаговых я в ступоре! Моя ОС gentoo, дрова и библитеки вроде бы собрал, но почему то ничего не могу скомпилировать. ни один пример ни с интернета, ни с сайта alsa. например вот это

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sched.h>
#include <errno.h>
#include <getopt.h>
#include <alsa/asoundlib.h>
#include <sys/time.h>
#include <math.h>
static char *device = "plughw:0,0"; /* playback device */
static snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; /* sample format */
#define METHOD SND_PCM_ACCESS_RW_INTERLEAVED
static unsigned int rate = 44100; /* stream rate */
static unsigned int channels = 2; /* count of channels */
static unsigned int period_time; /* period time in us */
double freq1 = 440; /* sinusoidal wave frequency in Hz */
double freq2 = 440; /* sinusoidal wave frequency in Hz */
short c1 = 0, c2 = 0, A1 = 32700, A2 = 32700;
int size;
static int verbose = 0; /* verbose flag */
static snd_output_t *output = NULL;
double dtime(){
    struct timeval ct;
    struct timezone tz;
    gettimeofday(&ct, &tz);
    return (ct.tv_sec + ct.tv_usec/1e6);
}
static int xrun_recovery(snd_pcm_t *handle, int err){
    if (err == -EPIPE) { /* under-run */
        err = snd_pcm_prepare(handle);
        if (err < 0)
         printf("Can't recovery from underrun, prepare failed: %s\n", snd_strerror(err));
        return 0;
    } else if (err == -ESTRPIPE) {
        while ((err = snd_pcm_resume(handle)) == -EAGAIN)
         usleep(1); /* wait until the suspend flag is released */
        if (err < 0) {
         err = snd_pcm_prepare(handle);
         if (err < 0)
         printf("Can't recovery from suspend, prepare failed: %s\n", snd_strerror(err));
        }
        return 0;
    }
    return err;
}
static int write_loop(snd_pcm_t *handle_o){
    double time0, time, _2pi = 2.*M_PI;
    unsigned char tmp;
    int i, s1, s2, _ss;
    snd_pcm_sframes_t err;
    double rnd1, rnd2, rate;
    time0 = dtime();
    char *rdata = (char *) malloc(size);
    _ss = size / 4;
    rate = period_time / _ss;
    short *data = (short*) rdata;
    snd_pcm_nonblock(handle_o, 1);
    while(1){
        time = dtime() - time0;
        for(i = 0; i < _ss; i+=2){
            s1 = c1+A1*cos((time+((double)i)*rate)*_2pi*freq1);
            s2 = c2+A2*cos((time+((double)i)*rate)*_2pi*freq2);
            if(s1 < -32700)    data[i] = -32700;
            else if(s1 > 32700) data[i] = 32700;
            else data[i] = s1;
            if(s2 < -32700)    data[i+1] = -32700;
            else if(s2 > 32700) data[i+1] = 32700;
            else data[i+1] = s2;
        }
        err = snd_pcm_writei(handle_o, rdata, size);
        if (err < 0)
            err = snd_pcm_recover(handle_o, err, 0);
        if (err < 0){
            printf("snd_pcm_writei failed\n");
            break;
        }
    }
}
int main(int argc, char *argv[]){
    snd_pcm_t *handle_o;
    int err, morehelp;
    snd_pcm_hw_params_t *hwparams_o;
    snd_pcm_sw_params_t *swparams_o;
    snd_pcm_uframes_t frames;
    unsigned int chn, val;
    if(argc==2) freq1 = freq2 = atof(argv[1]);
    else if(argc == 3){
        freq1 = atof(argv[1]);
        freq2 = atof(argv[2]);
    }
    printf("Playback device is %s\n", device);
    printf("Stream parameters are %iHz, %s, %i channels\n", rate, snd_pcm_format_name(format), channels);
    printf("Sine wave rate is (%.4f/%.4f)Hz\n", freq1, freq2);
    if ((err = snd_pcm_open(&handle_o, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
        printf("Playback open error: %s\n", snd_strerror(err));
        return 0;
    }
    snd_pcm_hw_params_alloca(&hwparams_o);
    snd_pcm_hw_params_any(handle_o, hwparams_o);
    snd_pcm_hw_params_set_access(handle_o, hwparams_o, METHOD);
    snd_pcm_hw_params_set_format(handle_o, hwparams_o, format);
    snd_pcm_hw_params_set_channels(handle_o, hwparams_o, 2);
    val = 44100;
    snd_pcm_hw_params_set_rate_near(handle_o, hwparams_o, &val, &err);
    frames = 128;
    snd_pcm_hw_params_set_period_size_near(handle_o, hwparams_o, &frames, &err);
    printf("set period size = %d: %s\n", frames, snd_strerror(err));
    err = snd_pcm_hw_params(handle_o, hwparams_o);
    if (err < 0) {
        printf("unable to set hw parameters: %s\n", snd_strerror(err));
        exit(1);
    }
    snd_pcm_hw_params_get_period_size(hwparams_o, &frames, &err);
    size = frames * 4;
    snd_pcm_hw_params_get_period_time(hwparams_o, &period_time, &err);
    printf("Period size: %dx4, period time: %d\n", frames, period_time);
    if (verbose > 0){
        snd_pcm_dump(handle_o, output);
    }
    snd_pcm_prepare(handle_o);
    err = write_loop(handle_o);
    if (err < 0)
        printf("Transfer failed: %s\n", snd_strerror(err));
    snd_pcm_close(handle_o);
    return 0;
}

или вот здесь http://www.alsa-project.org/alsa-doc/alsa-lib/examples.html ошибки компиляции примерно такие: /home/diesel/Projects/tuner/main.cpp:30: undefined reference to `snd_pcm_prepare'

объясните, люди добрые, чего я не догоняю или помогите

Я советую использовать JACK. У него и api человеческий, и кроссплатформенность заодно будет.

kranky ★★★★★
()
Ответ на: комментарий от kranky

Подскажите тогда где есть информация и примеры с JACK, по считыванию сустройств, и обработке аудио!?

Drdiesel
() автор топика
Ответ на: комментарий от kranky

Ну, ладно, еще куда тоже не шло, я уже и на альсо малех написать успел. Только трудное самое впереди! Мне нужно сравнивать частоты, а об этом еще сложнее что то найти. В JACK это трудно реализуемо?

Drdiesel
() автор топика
Ответ на: комментарий от Drdiesel

>В JACK это трудно реализуемо?

Это уже не имеет никакого отношения к аудио-либе. На питоне+jack подобный тюнер занял строк 100 (я тоже писал подобную фигню, когда изучал петон).

kranky ★★★★★
()
Ответ на: комментарий от Drdiesel

>я хочу сделать кое что похожее на gtkguitune например

Так я не против, делай =) Документации по jack'у в сети навалом. Можешь ещё исходники Kguitune и qpitch посмотреть, но там всё через Алсу сделано.

kranky ★★★★★
()
Ответ на: комментарий от Drdiesel

>Мне нужно сравнивать частоты, а об этом еще сложнее что то найти. В JACK это трудно реализуемо?

Как уже заметили, это не джека дело. А надо тебе вот, что:

1) Делаешь преобразование Фурье входного сигнала.

2) Откидываешь вторую половину результата. Откидываешь все нижнии частоты до.. скажем 40Гц.

3) Их оставшихся находишь максимум.

4)????7

5) ПРОФИТ

Waterlaz ★★★★★
()
Ответ на: комментарий от Waterlaz

Ну ка ну-ка поподробнее! Я понял, что не важно как я буду считывать входной поток и что для этого буду использовать JACK или ALSA. Я так и не смог разобраться. Смотрел разных исходники программ, но там все как правило привязано к GTK например, и вытащить оттуда обработку мне будет не по силам... Расскажите плиз, как сделать привязку входного канала и как его обрабатывать?

Drdiesel
() автор топика
Ответ на: комментарий от Drdiesel

>Расскажите плиз, как сделать привязку входного канала

Я таки рекомендую ознакомиться с документацией от джека, альсы или хоть чего-нибудь.

как его обрабатывать?


А это уже тебе решать, в зависимости от того, что ты хочешь получить. Если хочешь определить частоту входного сигнала - преобразуй его в фурье-спектр (man Преобразование Фурье), или ищи автокорреляцию (как в том же guitune или qpitch).

Алсо всякие способы определения частоты гармонического сигнала описаны даже в википедии.

kranky ★★★★★
()
Ответ на: комментарий от Drdiesel

Поищи в википедии «Дискретное преобразование Фурье». Оно как раз и дает тебе комплексные амплитуды синусоид. Что-бы получить вещественные, просто возьми их по модулю. Если подробно, то план такой(вообще, лучше бы ты до этого дошел сам):

1) Считываешь из входа кусок сигнала. Не сильно короткий. Допустим, 0.2с. При частоте дискретизации 44100, это будет 4410 семпла.

2) Прямое дискретное преобразование Фурье даст тебе из них 4410 комплексных числа. Из которых вторая половина тебя не интересует вовсе.

3) И так, у тебя 2205 комплексных числа. Берешь их всех по модулю.

4) k-ое число |Xk| есть амплитуда сигнала с частотой k/0.2 Гц.

5) Но тебя не должны интересовать совсем низкие частоты, поэтому откидываешь все до 40Гц. Это будет все вплоть до k=8.

6) Из чисел |Xk| находишь максимальное. Соответственно получешь и частоту.

Waterlaz ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.