[Решено] ALSA смещен ноль

Модератор: Модераторы разделов

Warlornhor
Сообщения: 428
ОС: openSUSE 12.3

[Решено] ALSA смещен ноль

Сообщение Warlornhor »

Пользуюсь ALSA для записи звука с микрофона, работает вроде как все нормально почти, но 0 сдвинут вниз, т.е. когда нет сигнала это например -0.2 в значении амплитуды в конкретный момент. 0 мне нужен для отсечение сигнала от не сигнала, например считаем что все что по модулю меньше 0.05 это шум и не обрабатываем в дальнейшем, а этот сдвиг не дает так сделать.

Может кто знает где это смещение настраивается или подскажет на какие алгоритмы посмотреть для калибровки микрофона?
Спасибо сказали:
Warlornhor
Сообщения: 428
ОС: openSUSE 12.3

Re: [Решено] ALSA смещен ноль

Сообщение Warlornhor »

Подумал и пришел к выводу что можно делать fft на буфере который был считан, рассматривать разницу минимального и максимального значения и если она меньше чем сколько-то, то это шум иначе начало сигнала. Но, этот вариант может оказаться слишком медленным. Так что я еще открыт для идей.
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: [Решено] ALSA смещен ноль

Сообщение NickLion »

Откуда значение -0.2? Амплитуда — абсолютная величина и не может быть меньше 0. Если измерение в dB, то абсолютная тишина — это минус бесконечность. В этом случае порог может быть любым, т.к. dB — относительная характеристика. Если имеется в виду, что сигнал равен -0.2, то в таком случае значение не может означать тишину, тишина — это отсутствие колебаний. Самый простой способ в данном случае — найти минимум и максимум за некоторый промежуток времени, если max-min < порога, то тишина.
Спасибо сказали:
Warlornhor
Сообщения: 428
ОС: openSUSE 12.3

Re: [Решено] ALSA смещен ноль

Сообщение Warlornhor »

Да, с утверждением согласен на счет просто разницы max-min. Опять же основная задача в том что нужно определить начало полезного сигнала, ну и конец соответственно.

На счет почему именно -0.2 не знаю почему так, цифра взята из вывода преобразованных двух байт в double, она такая же, например, в audacity если ничего не говорить, то полоса идет ниже 0.
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: [Решено] ALSA смещен ноль

Сообщение NickLion »

Ну да, сам уровень не значит ничего. Стоит буфер держать даже, когда сигнала нет, и как только сигнал станет оличаться более порога, то взять с небольшим участком времени до этого.

Подробнее:
Длина буфера = T отсчётов, период достаточный, чтобы отличить тишину, от малого затишья.
С одной стороны данные попадают от источника аудио. С другой стороны идёт запись, если необходимо. Т.е. буфер представляет очередь, реальная запись идёт с некоторой задержкой.
Начинаем с тишины, запись отключена.
Если в буфере max-min > порога, то включаем запись и данные уже находящиеся в буфере начинают попадать на запись.
Если в буфере max-min < порога, то запись выключаем, пустой буфер уже не попадёт никуда.
Спасибо сказали:
Warlornhor
Сообщения: 428
ОС: openSUSE 12.3

Re: [Решено] ALSA смещен ноль

Сообщение Warlornhor »

Не взлетит, например нет сигнала это числа типа

Код: Выделить всё

-0.1 -0.11 -0.09

Есть сигнал

Код: Выделить всё

-0.8 -0.79 -0.81


Очевидно, что разница max-min одинаковая. Если брать модуль, то в теории модно стремиться к нулю при некоторых обстоятельствах, но на практике я вчера пробовал получается не то что хотелось бы.
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: [Решено] ALSA смещен ноль

Сообщение NickLion »

Если постоянно идёт около -0.8 — это нет сигнала, поскольку колебания отсутствуют.
Спасибо сказали:
Warlornhor
Сообщения: 428
ОС: openSUSE 12.3

Re: [Решено] ALSA смещен ноль

Сообщение Warlornhor »

Вот так вот по идее работает.

Нахождение времени начала и конца

Код: Выделить всё

string fileName = argv[1];
    int sampleSize = 64;
    int samplesPerSecond = 8000;
    double startTime = 0;
    double endTime = 0;
    int sampleCounter = 0;
    bool startFound = false;
    bool endFound = false;
    double expSilenceTime = 0.1;
    double silenceTime = 0;
    vector<double> ampls = getAmplList(fileName, false, 0.05, 0.1, true);

    for (int i  = 0; i < ampls.size() - sampleSize; i += sampleSize) {
        vector<double> samples;
        for (int j = 0; j < sampleSize; j++) {
            samples.push_back(ampls[i + j]);
        }
        vector<double> energyArr = createSpectr(samples);
        bool signalFound = hasSignal(energyArr);
        if (signalFound && !startFound) {
            startTime = (double)sampleCounter * ((double)sampleSize / (double)samplesPerSecond);
            startFound = true;
        } else if (!endFound && startFound && !signalFound && silenceTime > expSilenceTime) {
            endTime = (double)sampleCounter * ((double)sampleSize / (double)samplesPerSecond);
            endFound = true;
        } else if (startFound && !signalFound) {
            silenceTime += ((double)sampleSize / (double)samplesPerSecond);
        }
        for (vector<double>::iterator eIt = energyArr.begin(); eIt != energyArr.end(); eIt++) {
            printf("%f ", *eIt);
        }
        printf("\n");
        samples.clear();
        sampleCounter++;
    }
    printf("%f \n", startTime);
    printf("%f \n", endTime);


Код который считает спектр и анализирует его, грубо, но должно работать, проверено только на wav файле, надеюсь с микрофоном будет аналогично работающе:

Код: Выделить всё

bool hasSignal(vector<double> &energyArr) {
    for (vector<double>::iterator eIt = energyArr.begin(); eIt != energyArr.end(); eIt++) {
        if (*eIt > 1) return true;
    }
    return false;
}

vector<double> createSpectr(vector<double> &ampls) {
    int samplesAmount = ampls.size();
    double *in = (double*)fftw_malloc(sizeof(double)*samplesAmount);
    fftw_complex* out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*samplesAmount);
    fftw_plan p = fftw_plan_dft_r2c_1d(samplesAmount, in, out, FFTW_MEASURE);
    vector<double> energyArr;

    for (int i = 0; i < samplesAmount; i++)
        in[i] = ampls[i];

    fftw_execute(p);

    for (int i = 0; i < samplesAmount/2 ; i++)
        energyArr.push_back(sqrt(out[i][1]*out[i][1] + out[i][0]*out[i][0]));

    return energyArr;
}


Если надо обрезать частоты то вот так:

Код: Выделить всё

void cutOffUnneededFreqs(vector<double> &energyArr, int minFreq, int maxFreq, int fRate) {
    int max_freq = fRate/2;
    int freq_step = max_freq/energyArr.size();
    int hiBound = 0, loBound = 0;
    if((max_freq - maxFreq) > 0)
        hiBound = (max_freq - maxFreq)/freq_step;
    loBound = minFreq/freq_step;
    energyArr.resize(energyArr.size() - hiBound);
    int i = 0;
    while( i < loBound)
    {
        energyArr.erase(energyArr.begin());
        i++;
    }
}
Спасибо сказали: