Работая над проектом, я столкнулся с необходимостью точно генерировать различные волны. Я думал, что простая синусоида будет проще всего начать, но, похоже, я ошибаюсь. Я сделал простую программу, которая генерирует vector
сэмплов, а затем воспроизводит эти сэмплы, чтобы пользователь услышал волну в качестве теста. Вот соответствующий код:
vector<short> genSineWaveSample(int nsamples, float freq, float amp) {
vector<short> samples;
for(float i = 0; i <= nsamples; i++) {
samples.push_back(amp * sinx15(freq*i));
}
return samples;
}
Я не уверен, что проблема с этим. Я понимаю, что может быть некоторая проблема с вектором, сделанным из short
s, но это то, чего хочет моя звуковая инфраструктура, и я неопытен с такой библиотекой и поэтому не знаю, чего ожидать.
Симптомы следующие:
Кто-нибудь может дать совет, что я могу делать не так?
Вот что я пробовал до сих пор:
Спасибо. Если есть какая-либо информация, которая может вам помочь, я буду обязан предоставить ее.
Я подозреваю, что вы передаете неверные значения sin15x функция. Если вы знакомы с основами обработки сигналов, Частота Найквиста это минимальная частота, на которой вы можете точно восстановить (или в вашем случае построить) дискретизированный сигнал. Определяется как 2x самая высокая частотная составляющая, присутствующая в сигнале.
Для вашей программы это означает, что вам нужно по крайней мере 2 значения за цикл наивысшей частоты, которую вы хотите воспроизвести. При 20 кГц вам понадобится 40000 выборок в секунду. Похоже, что вы просто упаковываете вектор со значениями и позволяете программе воспроизведения выбирать время.
Мы будем считать, что вы используете частоту дискретизации при воспроизведении 44,1 кГц. Это означает, что фрагмент кода, генерирующий одну секунду волны 1 кГц, будет выглядеть
DataStructure wave = new DataStructure(44100) // creates some data structure of 44100 in length
for(int i = 0; i < 44100; i++)
{
wave[i] = sin(2*pi * i * (frequency / 44100) + pi / 2) // sin is in radians, frequency in Hz
}
Вам нужно делить на частоту, а не умножать. Чтобы увидеть это, рассмотрим случай передачи значения частоты 22 050 Гц. Для i = 0 вы получаете sin (0) = 1. Для i = 1, sin (3pi / 2) = -1 и так далее, и так далее. Это дает вам повторяющуюся последовательность 1, -1, 1, -1 …, которая является правильным представлением волны 22,050 Гц, сэмплированной с частотой 44,1 кГц. Это работает, когда вы понижаете частоту, но вы получаете все больше и больше семплов за цикл. Интересно, что это не имеет значения. Синусоидальная выборка с частотой 2 выборки за цикл воссоздается точно так же, как и выборка с 1000 выборок в секунду. Это не учитывает шум, но для большинства целей работает достаточно хорошо.
Я бы посоветовал изучить основы цифровой обработки сигналов, поскольку это очень интересная область и очень полезная для понимания.
Редактировать: Предполагается, что все эти параметры оцениваются как числа с плавающей запятой.
По сути, вы упускаете часть информации. Вы не указываете время, за которое вы хотите, чтобы ваши образцы были взяты. Это также можно рассматривать как скорость, с которой сэмплы будут воспроизводиться вашей системой. Что-то в этом направлении приблизит вас, но пока.
samples.push_back(amp * std::sin(M_PI / freq *i));