Я изучаю Pure Data, в частности, я использую puredata vanilla 0.46.7
. У меня все хорошо с основами: создание и управление звуковыми сигналами, управление и обмен сообщениями, использование абстракций и т. Д. c.
У меня была идея иметь вертикальный слайдер внутри основного патча, который идет от От 0 до 1000, чтобы я мог настроить его, не нажимая Shift. Тем не менее, я хотел бы задать ему определенный c диапазон, например, от -10 до 10, и я мог бы сделать это, просто установив диапазон ползунка.
Я не сразу подумал об этом, поэтому я попробовал этот подход: у меня будет выходное отверстие ползунка, подключенное к входному отверстию range arg1 arg2
, что будет абстракцией, так что, например, путем создания range -10 10
диапазона ползунка (0..1000 ) будет сопоставлен диапазону, указанному в качестве аргументов объекта (-10..10).
Итак, я создал этот патч ( здесь - это ссылка на его вставку):
Я думал, что это было довольно легко, и я ожидал успеха, но безрезультатно. Вместо того, что входит в диапазон -10..10, вместо этого я получаю -10..0. Как я уже говорил ранее, я мог бы просто установить диапазон непосредственно на слайдере, но тот факт, что это не работает, означает, что я что-то упустил, поэтому я хотел бы знать, в чем заключается ошибка в моих рассуждениях, чтобы лучше понять, как работает уровень контроля чистых данных.
Основываясь на том, что я узнал о горячих и холодных входах, подключив [loadbang]
к [t b b]
, [f $2]
, а затем [f $1]
, произойдет следующее: что когда я создаю новый [range]
(например, range -10 10
), [f $2]
равен banged
, что заставляет объект выводить второй аргумент, переданный в [range]
($2
). Поскольку выход объекта подключен к холодным входам двух [expr]
, он просто находится там, и объекты [expr]
должны вывести свое значение по умолчанию (равное 0).
Затем, [t b b]
should bang [f $1]
: это заставляет объект выводить первый аргумент. Поскольку его выход подключен к горячим входам объектов 2 [expr]
, это должно привести к тому, что два объекта выведут результат своих выражений.
Они проверяют, равны ли $1
и $2
0, что означает, что для [range]
не было предоставлено никаких аргументов. В этом случае первый [expr]
выводит 0 (минимальное значение по умолчанию), второй выводит 1 (максимальное значение по умолчанию). В противном случае они просто выводят все, что нужно: первые [expr]
выводят $f1
(что является минимальным значением, хранящимся в [f $1]
); вторые [expr]
выходы $f2
(максимальное значение, сохраненное в [f $2]
.
Выходы объекта [expr]
подключены к входам [swap]
, затем его выходы подключены к [- ]
. Итак, я передал -10 и 10 в качестве аргументов, минимальное значение -10, максимальное значение 10, их поменяли местами и затем вычли, что означает, что [- ]
теперь должно вывести 20 (10 - (-10)): это диапазон, в котором я хочу отобразить 0..1000.
[inlet]
из range
- это значение, полученное от ползунка: я делю его на 1000, чтобы он находится в диапазоне 0..1. Давайте назовем это число n
. Теперь я хочу сопоставить n
с -10..10, поэтому я придумал эту формулу: x = R * n + m
, где R
это ранее вычисленный диапазон, а m
- это минимальное значение, которое действует как смещение. Таким образом, если 500 - это значение ползунка, n = 0.5
. Для R = 20
и m = -10
это означает, что x = 0.0
, что ожидается: 500 находится в середине 0..1000, а 0.0 - в середине -10..10.
Это именно то, что последний [expr]
объект делает: $f1
- это значение из ползунка, $f2
- это R
(диапазон), а $f3
- m
(минимум, или смещение).
На данный момент, учитывая, как предыдущие объекты связаны, я должен иметь правильные значения для $f2
и $f3
. Если значение ползунка изменяется, я должен увидеть соответствующий вывод, но это неправильно: вместо отображения на -10..10 он отображается на -10..0.
Поскольку я не могу отлаживать, как на языке программирования "classi c" (то есть go шаг за шагом при выполнении кода), я подключил [print]
объекты к соответствующим выходам, чтобы проверить порядок операций. Затем я создал [range -10 10]
на основном патче и прочитал консоль, чтобы увидеть отпечатки. Я получил этот «след»:
arg2: 10
swap-dx: -10
range: 10
swap-sx: 0
check-min: -10
check-max: 10
arg1: -10
Это сбивает с толку, учитывая приведенные выше рассуждения о входах горячей / холодной воды и о том, как я соединял различные объекты, я ожидал что-то вроде:
arg2
arg1
check-min
check-max
swap-sx
swap-dx
range
Я не могу понять смысл полученного следа: как это возможно, что swap-dx
сразу после arg2
? И как это возможно, что arg1
находится в самом низу? Я понимаю, что сообщения передаются "справа налево" относительно входов и "сначала глубины" относительно расположения объектов, но в этом случае, мне кажется, что нет пути от arg2
до swap
, поскольку выходы [f $2]
подключены к холодным входам, и соответствующие объекты не должны ничего выводить, пока что-то не изменится на их горячих входах.
Если я увидел что-то вроде arg2 -> check-min -> swap-dx -> range
, а затем все остальные, то было бы четким указанием на правило "глубина в первую очередь". Вместо этого я получил все вышеперечисленное.
Однако результат (тот факт, что диапазон изменяется от -10 до 0) согласуется с тем, что я вижу на графике: swap-sx: 0, swap-dx: -10, range: 10
, и это дает подсказку о проблеме. По какой-то причине горячий вход [swap]
никогда не обновляется и остается равным 0, поэтому [- ]
делает вычитание 0 - (-10)
, равное 10
. Следовательно, значение должно быть отображено на -10..0.
Я проверил каждую «стадию» индивидуально, убедившись, что все объекты ведут себя так, как я ожидал, и они делают: выражения кажутся правильными, есть нет причуда с [- ]
: если я передам -10 к его холодному входу и 10 к его горячему входу, выход будет 20, что правильно.
Итак, ясно, что все это .. неясно мне: что я делаю не так? Что я мог бы сделать для более эффективной отладки патча, кроме размещения объектов [print]
везде? Должен ли я использовать [float]
объекты для хранения значений на каждом этапе, используя тот факт, что они выводятся только тогда, когда они стучат по горячему входу, а затем использовать триггер, чтобы стучать по ним в нужном порядке? Мне это кажется излишним и головной болью.