Рассчитать пилообразную и треугольную волну по конкретным данным

Мне нужно рассчитать треугольник и пилообразную волну, но это немного сложно из-за моей модели и данных, с которыми я могу работать (но, возможно, я просто запутался).

Я могу рассчитать свою синусоиду, но на самом деле я не использую счетчик кадров. Что я делаю, так это вычисляю переменную theta_increment, которую я могу использовать в следующий раз, когда мне нужно будет рассчитать выборку. Это работает следующим образом:

float x = note.frequency / AppSettings::sampleRate;
float theta_increment = 2.0f * M_PI * x;
float value = 0;

if(waveType == SINE){
    value = sin(note.theta) * fixedAmplitude;
}

Теперь, когда у меня есть значение текущего фрейма/образца, я сохраняю theta_increment внутри своего члена note.theta, чтобы использовать его для следующего образца:

note.theta += theta_increment;

Я просмотрел множество примеров того, как я должен вычислять пилу или треугольник, но я не могу понять это. (В моем распоряжении есть только данные, упомянутые выше) Это моя последняя попытка, но она не работает и дает мне массу сбоев:

value = 1.0f - (2.0f * ((float)note.theta / (float)44100));

person Community    schedule 18.08.2012    source источник


Ответы (2)


Если у вас есть цикл, генерирующий ваши значения следующим образом:

for (size_t frame=0; frame!=n_frames; ++frame) {
  float pos = fmod(frequency*frame/sample_rate,1.0);
  value[frame] = xFunc(pos)*fixedAmplitude;
}

Затем вы можете использовать эти функции для разных типов волн:

float sinFunc(float pos)
{
  return sin(pos*2*M_PI);
}

float sawFunc(float pos)
{
  return pos*2-1;
}

float triangleFunc(float pos)
{
  return 1-fabs(pos-0.5)*4;
}

Основная идея заключается в том, что вам нужно значение (pos), изменяющееся от 0,0 до 1,0 в каждом цикле. Затем вы можете формировать это, как хотите.

Для синусоидальной волны функция sin() выполняет свою работу, вам просто нужно умножить на 2 * PI, чтобы преобразовать диапазон от 0,0 до 1,0 в диапазон от 0,0 до 2 * PI.

Для пилообразной волны вам просто нужно преобразовать диапазон от 0,0 до 1,0 в диапазон от -1,0 до 1,0. Умножение на два и вычитание одного делает это.

Для треугольной волны вы можете использовать функцию абсолютного значения, чтобы вызвать внезапное изменение направления. Сначала мы преобразуем диапазон от 0,0 до 1,0 в диапазон от -0,5 до 0,5, вычитая -0,5. Затем мы превращаем это в форму от 0,5 до 0,0 до 0,5, взяв абсолютное значение. Умножая на 4, мы преобразуем это в форму от 2,0 до 0,0 и до 2,0. И, наконец, вычитая его из единицы, мы получаем форму от -1,0 до 1,0 до -1,0.

person Vaughn Cato    schedule 18.08.2012
comment
Любая идея, как я могу установить диапазон от -1 до 1? Я думаю, это уже относится к синусоидальной функции, но как насчет двух других? - person ; 02.09.2012
comment
@Sled: функции имеют диапазон от -1 до 1, как указано. - person Vaughn Cato; 02.09.2012
comment
Я попробовал это, нарисовав их, и диапазоны, которые я получаю на графике, сильно отличаются: jsfiddle.net/DsCXH есть идеи, что я делаю не так? - person ; 03.09.2012
comment
@Sled: Код там отличается от того, что я описал. Например, он не использует модуль. В вашем коде тета находится в диапазоне от 0 до 2*PI, и вы используете тета так, как если бы она была эквивалентна pos в моем коде, где pos находится в диапазоне от 0 до 1. - person Vaughn Cato; 03.09.2012
comment
Мне просто интересно, производит ли sinFunc тон на одну октаву выше. Он должен возвращать sin(pos * M_PI), а не sin(pos * 2 * M_PI). Но я рад видеть этот треугольникFunc ... :-) - person Edgar Alloro; 09.12.2016

Пилообразную волну можно рассчитать следующим образом:

value = x - floor(x);

Треугольник можно рассчитать следующим образом:

value = 1.0 - fabs(fmod(x,2.0) - 1.0);

где х равно note.theta.

person user1118321    schedule 18.08.2012
comment
Они отлично работают. Еще один вопрос: есть шанс, что вы знаете формулу перевернутой пилы? - person ; 18.08.2012
comment
Вы можете перевернуть его, выполнив 1 - sawtooth(x);. Это то, что вы имели ввиду? Или, может быть, вы имели в виду что-то вроде value = sawtooth(-x);. Вероятно, есть несколько разных способов, в зависимости от того, что вы ищете. - person user1118321; 18.08.2012
comment
Эй, еще один вопрос по этому поводу: есть идеи, как я могу указать диапазон значений от -1 до 1 для каждой из этих функций? - person ; 02.09.2012
comment
умножить на 2 и вычесть 1. - person user1118321; 02.09.2012
comment
Для формул, которые я написал, да. Их выход всегда находится в диапазоне от 0 до 1. Умножение на 2 приводит к тому, что выход находится в диапазоне от 0 до 2. Вычитание 1 уменьшает диапазон до значений от -1 до 1. - person user1118321; 02.09.2012