كيفية إيقاف موضع تعديل مؤقتًا واستئنافه عكسيًا عند الإشارة التالية في SuperCollider
لإيقاف موضع تعديل مؤقتًا واستئنافه عكسيًا، أبقِ مولّد الطور قيد التشغيل بزيادة تساوي صفرًا، ثم بدّل تلك الزيادة إلى قيمة سالبة عند الإشارة التالية. اترك مدخل إعادة ضبط الطور غير موصول بهذه الإشارات كي تستمر الحركة من الموضع المثبّت.
يبني هذا الدرس هذا السلوك في SuperCollider: يتوقف مسح تصاعدي للنغمة عند الإشارة الأولى، ثم يعود على مساره عند الثانية. وهو موجّه إلى مصمم صوت يريد إيماءة تعديل قابلة للتكرار، تتحكم فيها أحداث متعاقبة. ويمكن لاحقًا استخدام إشارة الطور نفسها للتحكم في معلمة أخرى.
ما الذي يجب الحفاظ عليه أثناء التوقف المؤقت؟
تعامل مع التعديل بوصفه عمليتين مترابطتين: يتحرك موضع عبر دورة، وتحول خريطة ذلك الموضع إلى قيمة معلمة مفيدة. هنا، ينتقل الموضع من الصفر باتجاه الواحد، وتحوله الخريطة إلى تردد للمذبذب.
يوفر Phasor في SuperCollider الموضع. تحدد وسيطته rate مقدار الزيادة لكل عينة؛ أما مدخل الإشارة فيه فيقفز إلى resetPos. وهذان عنصران منفصلان للتحكم، لذا ينبغي ألا تعيد الإشارة المستخدمة لتغيير الاتجاه ضبط الموضع أيضًا. توثيق Phasor
يحتفظ التنفيذ بمستوى داخلي ويضيف إليه المعدل. ووفقًا لهذا السلوك، يثبت المعدل الصفري المستوى، بينما يحركه المعدل السالب إلى أسفل. يطبق المقطع أدناه ذلك مباشرة، محافظًا على حالة المولّد طوال التوقف المؤقت. تنفيذ TriggerUGens.cpp في SuperCollider 3.14.0
ماذا ينبغي أن تفعل كل إشارة متعاقبة؟
حدد تسلسل الأحداث قبل توصيل الصوت. في هذا المقطع، تبدأ الحركة إلى الأمام فورًا. وتنقل كل إشارة لاحقة المقطع إلى حالة تالية:
| عدد الإشارات المستلمة | الحالة | معامل الاتجاه |
|---|---|---|
| 0 | تحرك إلى الأمام | +1 |
| 1 | ثبّت الموضع الحالي | 0 |
| 2 | استأنف الحركة إلى الخلف | −1 |
| 3 | ثبّت الموضع الحالي | 0 |
| 4 | استأنف الحركة إلى الأمام | +1 |
تفصل هذه الدورة ذات الحالات الأربع بين حالتي التثبيت: إحداهما تسبق الحركة إلى الخلف، والأخرى تسبق الحركة إلى الأمام. وهذا يجعل الإيماءات المتكررة قابلة للتوقع من دون الحاجة إلى زر اتجاه آخر.
يزيد PulseCount بمقدار واحد عندما تتغير إشارته من قيمة غير موجبة إلى قيمة موجبة. ويؤدي أخذ باقي قسمة العد على أربعة إلى إنتاج الفهارس المتكررة من 0 إلى 3. ثم يختار Select معامل الضرب المقابل من [1, 0, -1, 0]. وهذه هي الأدوار الموثقة لكل من PulseCount وSelect.
كيف تبني المقطع الكامل؟
استخدم تثبيتًا محليًا لـ SuperCollider مع خرج صوتي يعمل؛ ويتبع المثال توثيق الإصدار 3.14.0. وهو يستخدم مولدات الوحدات المدمجة وينشئ صوته بنفسه، لذا لا يتطلب ملفات عينات أو امتدادات. قيّم الكتلة كاملة مرة واحدة وانتظر رسالة الجاهزية.
يبدأ waitForBoot الخادم عند الحاجة. يُرسل التعريف قبل إنشاء المولّد، مع انتظار s.sync اكتمال عمليات الخادم المعلّقة. راجع توثيق Server وتوثيق SynthDef.
(
s = Server.default;
s.waitForBoot({
SynthDef(\pauseReverseMod, {
|out = 0, t_step = 0, cycleSeconds = 8, amp = 0.08|
var state, direction, increment, phase, frequency, sound;
state = PulseCount.kr(t_step) % 4;
direction = Select.kr(state, [1, 0, -1, 0]);
// A full 0..1 traversal takes cycleSeconds seconds.
increment = direction * SampleDur.ir
/ cycleSeconds.max(0.01);
// State-changing triggers never reset this phase.
phase = Phasor.ar(
trig: 0,
rate: increment,
start: 0,
end: 1,
resetPos: 0
);
frequency = LinExp.ar(phase, 0, 1, 220, 880);
sound = SinOsc.ar(frequency, 0, amp);
Out.ar(out, sound ! 2);
Poll.kr(Impulse.kr(2), state, "state");
Poll.kr(Impulse.kr(2), A2K.kr(phase), "phase");
}).add;
s.sync;
~pauseReverseSynth = Synth(\pauseReverseMod);
"Ready: evaluate ~pauseReverseSynth.set(\\t_step, 1);".postln;
});
)
الزيادة هي الاتجاه مضروبًا في مدة العينة ومقسومًا على مدة الدورة. تعيد SampleDur مقلوب معدل أخذ العينات للخادم، لذا لا يفترض إعداد الثماني ثوانٍ معدل أخذ عينات بعينه. توثيق SampleDur
يمتد تحويل النغمة من 220 إلى 880 هرتز. تحول LinExp نطاق دخل خطيًا إلى نطاق خرج أسي؛ ويجب ألا تكون نهايتا الوجهة صفريتين وأن تكون لهما الإشارة نفسها. وتحقق النهايتان هنا هذا الشرط. توثيق LinExp
راجعت مثال SuperCollider بالاستناد إلى التوثيق المسترجع. لم تكن بيئة تشغيل SuperCollider متاحة في بيئة البحث، لذا لم أنفذ هذا المقطع أو أستمع إليه. وتحقق حسابي حتمي منفصل من تسلسل الاتجاه وسلوك التثبيت عند الزيادة الصفرية.
كيف توقف الحركة مؤقتًا وتستأنفها إلى الخلف؟
بعد ظهور رسالة الجاهزية، اترك النغمة ترتفع نحو ثانيتين. ثم قيّم أمر التفاعل هذا مرة واحدة:
~pauseReverseSynth.set(\t_step, 1);
ينبغي أن تصبح الحالة 1، وأن يستقر الطور عند قيمة واحدة. انتظر قليلًا، ثم قيّم الأمر نفسه مرة أخرى. ينبغي أن تصبح الحالة 2، وأن ينخفض الطور انطلاقًا من الموضع المثبّت. ويؤدي التقييم الثالث إلى تثبيت المسح الهابط، بينما يبدأ التقييم الرابع حركته إلى الأمام مجددًا.
تجعل السابقة t_ من t_step عنصر تحكم للإشارة. ويؤدي ضبطه إلى إنشاء نبضة بمعدل التحكم، ما يسمح باستخدام الأمر نفسه مرارًا من دون إرسال صفر منفصل يدويًا بين التقييمات العادية المتباعدة. توثيق عنصر التحكم للإشارة في SynthDef
في حساب توضيحي للتوقيت، تتقدم دورة مدتها ثماني ثوانٍ بمقدار 0.125 من نطاقها في الثانية. لذا فإن التوقف بعد ثانيتين يثبت الموضع عند نحو 0.25. وبعد أي مدة من التوقف، تنقله ثانية واحدة من الحركة إلى الخلف إلى نحو 0.125. هذه قيم متوقعة محسوبة؛ أما التوقيت الفعلي للأوامر يدويًا فيحدد موضع التوقف الحقيقي.
لإنهاء التشغيل، قيّم أمر التنظيف:
~pauseReverseSynth.free;
كيف تتحقق من أن الموضع ظل ثابتًا فعلًا؟
استخدم الطور المطبوع بوصفه أداة التشخيص الأساسية. ينبغي أن يرتفع أثناء الحركة إلى الأمام، وأن يظل ثابتًا في كلتا حالتي التثبيت، وأن ينخفض أثناء الحركة إلى الخلف حتى يصل إلى حد الدورة.
يطبع المقطع القيم مرتين في الثانية، لذا تعرض الشاشة عينات من السلوك بدلًا من كل عينة. راقب عدة قراءات متتالية أثناء التوقف المؤقت، ثم قارنها بأول القراءات الهابطة بعد الاستئناف. صُممت Poll لتصحيح أخطاء قيم مولدات الوحدات؛ أزل سطري الاستقصاء عند تكييف التعريف للاستخدام المعتاد. توثيق Poll
هذا الاختبار أوضح من الاستماع وحده. فثبات الصوت يؤكد أن القيمة المستهدفة توقفت عن التغير، بينما تؤكد قراءة الطور المستقرة أن الموضع الأساسي توقف أيضًا. ويسهّل إبقاء الخريطة ثابتة طوال الاختبار تفسير النتيجة.
لماذا قد يُعاد تشغيل المقطع أو يقفز أو يفوّت إشارة؟
يُعاد تشغيله عند الاستئناف. تحقق مما إذا كان الحدث يصل أيضًا إلى مدخل الإشارة في Phasor. فهذا المدخل يعيد ضبط الموضع صراحةً. يظل عند الصفر في هذا المقطع، بينما تُرسل الأحداث إلى عدّاد الحالات فقط. توثيق Phasor
يقفز بعد بلوغ إحدى النهايتين. يتكرر هذا المثال عمدًا. يلتف التنفيذ بالطور ضمن نطاقه المحدد، حتى أثناء الحركة السالبة. وعندما تتجاوز الحركة إلى الخلف الصفر، يعود الطور إلى قرب الحد الأعلى، ما ينتج قفزة في النغمة مع خريطة المنحدر هذه. اختبر التوقف المؤقت وعكس الاتجاه بعيدًا عن ذلك الحد أولًا. تنفيذ Phasor
لا تنتج عدة أوامر سريعة عدة حالات. يحتاج العدّاد إلى انتقالات صاعدة منفصلة. تعمل عناصر التحكم للإشارة بمعدل التحكم، لذا لا تفترض أن عدة أوامر تصل ضمن كتلة تحكم واحدة ستتحول إلى أحداث منفصلة. ابدأ بأوامر متباعدة بوضوح؛ وللتسلسلات المضبوطة بدقة، صمم مصدر الأحداث بحيث يولد نبضات منفصلة. توثيق PulseCount، توثيق SynthDef
يتغير الصوت بينما الطور ثابت. تحقق مما إذا كنت تغير أيضًا خريطة القيمة المستهدفة أو معلمة صوت أخرى. في هذا الاختبار، أبقِ نهايتي النغمة ثابتتين واستخدم الطور المطبوع لعزل نقل التعديل.
الإيماءة المكتملة هي: إلى الأمام، ثم تثبيت، ثم إلى الخلف، ثم تثبيت، ثم إلى الأمام مجددًا. وبعد أن يعمل هذا التسلسل على نحو صحيح، احتفظ بعدّاد الحالات ومولّد الطور كمصدر تعديل قابل لإعادة الاستخدام، وغيّر خريطة القيمة المستهدفة لتناسب الصوت الذي تبنيه.
المصادر
- Phasor — مساعدة SuperCollider 3.14.0
- TriggerUGens.cpp — SuperCollider، الإصدار 3.14.0
- PulseCount — مساعدة SuperCollider 3.14.0
- Select — مساعدة SuperCollider 3.14.0
- Server — مساعدة SuperCollider 3.14.0
- SynthDef — مساعدة SuperCollider 3.14.0
- SampleDur — مساعدة SuperCollider 3.14.0
- LinExp — مساعدة SuperCollider 3.14.0
- Poll — مساعدة SuperCollider 3.14.0
