БПФ звукового сигнала (C++ и SFML)

238
25 октября 2017, 06:04

У меня вопрос по БПФ звукового сигнала. Я хочу нарисовать график на основе звукового сигнала. Но я не силен в этой теме. Хочу совета у опытных товарищей с чего начать.

У меня несколько вопросов: 1) Что такое samples (семплы)? Например при использовании мультимедийной библиотеки SFML для получения семплов используется следующая конструкция:

sf::Buffer Buffer;
Buffer.loadFromFile("sound.wav");
const sf::Int16 *input = Buffer.getSamples();

Так вот я так понимаю семплы это бинарное представление звукового файла? Я правильно понимаю, что вышепредставленный код, это тоже самое что и:

    typedef short int16;
    int16 *load()
    {
      FILE  *fp;
      if((fp=fopen("sound.wav", "rb"))==NULL) {
        printf("Ошибка при открытии файла.\n");
      }
      fseek(fp, 0, SEEK_END);
      long N = ftell(fp);
      fseek(fp, 0, SEEK_SET);
      int16 *A = new int16[N];
      for(i=0; i<N; i++)
        if(fread(A[i],
           sizeof(A), 1, fp)!=1) {
             if(feof(fp)) break;
             printf("Ошибка при чтении файла.\n");
        }
      fclose(fp);
      return A;
    }
    int16 *input = load(); 

Т.е. получить семплы, это тоже самое что получить бинарное представление файла в 16-битовом типе? Или я неправильно понимаю?

2) Вопрос 2: я знаю, что для БПФ существует быстрая библиотека FFTW. Также в викиучебнике есть реализация алгоритма БПФ на C++ (ссылка алгоритм: https://ru.wikibooks.org/wiki/Реализации_алгоритмов/Быстрое_преобразование_Фурье#C.2B.2B). Вопрос в следующем, что именно подается на вход в этом алгоритме? Массив с бинарным представлением файла, или семплы, взятые с помощью SFML? В данном алгоритме предполагается, что в качестве параметров передается массив с анализируемыми данными и массив с преобразованными данными. В качестве анализируемых данных что подразумевается? И что делать если размер массива не равен степени двойки? Это обязательное условие? Я так понимаю, что в приведенный по ссылке алгоритм дается полученный массив семплово, только преобразованный в double?

int16 *input[N];
double *in = new double[N];
in = input;
double *out = new double[N];
void FFTAnalysis(in, out, N, N)

В этом примере, я так понимаю N - это рамзер массива семплов, т.е. sizeof(input);

В той же библиотеке SFML количество семплов находится так:

unsigned long long N = Buffer.getSampleCount();

Еще я не понимаю почему размер массива семплов не равен количеству семплов, например, когда я делаю так:

sf::Buffer Buffer;
Buffer.loadFromFile("sound.wav");
unsigned long long N = Buffer.getSampleCount();
const sf::Int16 *raw = new sf::Int16[N];
raw = Buffer.getSamples();
printf("%hu", sizeof(raw));// == 4 - почему?, если N шестизначное 

В функцию: void FFTAnalysis(in, out, N, N) передаются массив анализируемых данных, и массив куда преобразованные данные записываются (double in и double out). А N - это размер этих массивов (количество семплов). Так вот по условию N всегда должно быть кратно степени двойки. А как быть если количество семплов не кратно степени двойки?

3) Когда мы получим массив преобразованных данных, на основе каких данных рисовать график? В качестве координат ее вершин (точек) брать мнимую часть спектра (т.е. элементы массива преобразованных данных) или спектр мощности? Другими словами, набор каких данных брать за координаты точек синусойды?

Должен получиться график, но я не пойму что брать за координаты точек? Когда я с помощью библиотеки SFML получаю количество семплов и сами семплы, и вывожу их в цикле через printf("%hu", raw[i]); в консоль, то я там вижу практически одни нули с редкими единицами. Как на основе этих данных можно нарисовать какую либо фигуру? значит семплы нужно предварительно обрабатывать прежде чем брать их за координаты точек?

Answer 1

Если речь идет о несжатом звуковом файле, то семпл - это отсчет, полученный при оцифровке сигнала, т.е. просто мгновенное значение амплитуды аналогового сигнала. По этим отсчетам можно построить вашу "синусойду", т.е. представление сигнала во временной области. БПФ же, это быстрое преобразование Фурье, выполнив его мы получаем отображение сигнала в частотной области (разложение сигнала по частотам). Как реализована конкретная библиотека я не знаю, но для алгоритма БПФ необходима кратность 2. Хотя можно и нолики в конце дописать, ну да ладно, это уже ЦОС. Рекомендую вам для начала ознакомится с теоретической стороной вопроса, чтобы четко понимать, что вы делаете. Успехов)

READ ALSO
Потерялся 1 бит в long double

Потерялся 1 бит в long double

По следам вопроса о битовом представлении вещественных чисел и моего ответа на него

225
set и unordered_set

set и unordered_set

Все мы знаем, что std::set - это красно-чёрное дерево (соответственно со сложностью поиска O(log n)), а std::unordered_set - хэш-таблица с поиском за константуКакие...

256
Увеличение времени исполнения кода

Увеличение времени исполнения кода

Столкнулся со следующей проблемой: Есть код, написанный не одним человеком, который работает с использованием MPIВ части последовательного...

203