Масштабирование целочисленных значений (от числа с плавающей запятой)

Я разрабатываю подключаемый модуль VST Audio, который требует извлечения данных об амплитуде из входящего сигнала, который будет использоваться для настроек скорости в области миди.

По сути, я буду получать значения от 0 до 1 (с плавающей запятой), и мне нужно преобразовать их в 0-127 int.

В настоящее время процесс будет заключаться в умножении значения с плавающей запятой на 100, чтобы получить целое значение +3 десятичных знака, то есть 103,4567685 ИЛИ 005,6778787282.

Отсюда я буду округлять числа с плавающей запятой до целых, используя функцию floor().

Однако это оставит мне значения от 0 до 100; однако мне нужно масштабировать их до 0-127.

Буду очень признателен за любые предложения о том, как это можно сделать возможным.


person Forge_13    schedule 27.01.2011    source источник


Ответы (7)


Если вы возьмете некоторые из представленных здесь предложений и умножите их на 127, вы обнаружите, что 127 не очень хорошо представлены в вашем выводе. Может быть, это не будет проблемой для вас, но есть небольшое изменение, которое имеет большое значение.

Вы можете подумать, что округление поможет, но это не так. Количество значений в 127 по-прежнему будет вдвое меньше, чем в других значениях, и теперь количество значений в 0 также будет вдвое меньше среднего.

Правильная формула:

int amplitude = static_cast<int>(value * (128-epsilon)); // where epsilon is a very small floating point value
person Mark Ransom    schedule 27.01.2011
comment
Вы не можете давать такие советы, не рассказав бедному ОП, как получить эпсилон! - person TonyK; 27.01.2011
comment
100 казалось ему приемлемым, так что 127, вероятно, есть/было, однако он мог не думать об этом или не замечать этого! - person winwaed; 27.01.2011
comment
@TonyK, точное значение эпсилон не очень важно для большинства реальных приложений. Вы можете использовать FLT_EPSILON из limits.h или numeric_limits<float>::epsilon() из limits, или просто любое небольшое число. Я бы не стал использовать numeric_limits<double>::epsilon(), потому что он действителен только для значения 1,0 и будет слишком мал для 128,0. - person Mark Ransom; 27.01.2011
comment
Вы не обращаетесь к моей точке зрения. (См. мой ответ для некоторого здравого смысла.) - person TonyK; 27.01.2011

Правильный способ сделать это:

int amplitude = 128 * value ;
if (amplitude == 128) amplitude = 127 ;
person TonyK    schedule 27.01.2011
comment
ТониК прав. Причина этого в том, что 64 является центральным значением для MIDI, реализации в MIDI-устройствах обычно используют описанный выше метод. - person Zuppa; 13.12.2012

Преобразование диапазона не так просто. В случае масштабирования целочисленного диапазона [-n; n] для float, использование наивного подхода простого умножения приводит к тому, что обратное отображение, скорее всего, не будет отображаться в исходные значения. Скажем, у вас есть набор всех чисел в диапазоне целых чисел и набор той же величины в диапазоне с плавающей запятой, наивное отображение не является биективным.

Есть хорошая статья об этом и пример кода о том, как реализовать монотонность и упорядочивать сопоставления с сохранением на http://kaba.hilvi.org/programming/range/index.htm

person datenwolf    schedule 27.01.2011

Просто умножьте свое значение на 127 и приведите его к int. [0,1]*127 => [0,127]

person Elalfer    schedule 27.01.2011
comment
-1: это не отображает все значения правильно - см., например. Ответ TonyK или ответ Mark R для лучшего решения - person Paul R; 06.12.2011

Я думаю, что я должен что-то упустить. почему бы не умножить на 127,0 вместо 100?

person winwaed    schedule 27.01.2011
comment
о, да. Я не думал об этом. я чувствую себя дураком - person Forge_13; 27.01.2011

Я использую этот эффективный обходной путь, чтобы покрыть все значения с помощью функции round().

выход = округлый (ампьеза * 127,5 + 127,5)

ampiezza — это число с плавающей запятой со знаком в диапазоне от -1 до +1, выход — 8-битное целое число.

выходной диапазон от 0 до 255 с центром между 127 и 128

Надеюсь, это может быть полезно.

person Fish    schedule 01.12.2018

Умножьте полученное значение на 1,27, прежде чем использовать floor()?

person Merijn    schedule 27.01.2011