2012-03-06 6 views
3

Я смотрю на это example about sound generation on iOS, потому что мне нужно сделать что-то подобное, но есть некоторые части, которые я не понимаю, и я надеялся, что кто-то сможет мне помочь.Генерация тона iOS

В этой части кода:

double theta_increment = 2.0 * M_PI * viewController->frequency/viewController->sampleRate; 
    // Generate the samples 
    for (UInt32 frame = 0; frame < inNumberFrames; frame++) 
    { 
     buffer[frame] = sin(theta) * amplitude; 

     theta += theta_increment; 
     if (theta > 2.0 * M_PI) 
     { 
      theta -= 2.0 * M_PI; 
     } 
    } 

Я не очень понимаю, что theta += theta_increment; часть для. Для меня имеет смысл делать что-то подобное внутри цикла for:

buffer[frame] = sin(theta_increment * frame); 

Любая идея, почему это не сработает? Кроме того, я понятия не имею, для чего эта часть кода предназначена для: if (theta > 2.0 * M_PI), поэтому любое объяснение этому было бы очень желанным.

ответ

1

Ваш подход может быть использован для создания одного и того же результата, выраженного по-разному. Однако theta += theta_increment; будет более простым выражением (для расчета), чем то, что вы предлагаете.

Домен фазы обернут до sin' s логическим доменом параметров. Этот шаг действительно не нужен для коротких образцов. Из-за ограничений в хранении с плавающей запятой ваша частота может в конечном счете меняться и в конечном счете никогда не увеличиваться, если значение не обернуто, в зависимости от количества образцов, которые вы генерируете, и используете ли вы float или double. Подумайте об этом так: что произойдет, если у вас есть огромный положительный номер с плавающей запятой (значение вашего фазового аккумулятора), и вы пытаетесь добавить к нему 0.000004? Ошибка с плавающей запятой округляет его, чтобы поместиться в поплавок или двойной, и ошибка приведет к фазе и, в конечном счете, неустойчивости шага. Для коротких образцов (например, некоторых циклов) обертка не нужна в этом случае, но для многих многих циклов она служит для стабилизации шага и фазового аккумулятора с течением времени.

И, наконец, theta будет использоваться для сохранения последнего значения фазовой рампы, чтобы возобновить генерацию, где она остановилась в следующем вызове визуализации. Без этого выход будет перезапущен на 0 при границах вызова визуализации, создавая очень неприятные шумы и неправильные частоты.

Считается, что это была простая демонстрация и быстрый способ генерации синуса в этом контексте. У вашего подхода есть несколько «дорогостоящих» конверсий, но он не является ветвящимся - он может быть быстрее исходного, esp для более высоких частот.

1

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

buffer[frame] = sin(theta_increment * frame) * amplitude; 

всего два различных способа выражения той же математике. Похоже, что человек, который написал оригинальный код, хотел сохранить 0 < = theta < 2pi, но это, вероятно, не обязательно (если вызов sin() не является странным в некотором смысле, о котором я не знаю). Кроме того, они могли бы захотеть сохранить «математическую» часть независимо от переменной кадра, если тот же фрагмент появится в других петлях в другом месте, но это всего лишь предположение.