Cara Memberi Setiap Nada yang Dimainkan Decay Reverb Berdasarkan Lama Nada Ditahan
Untuk memberi setiap nada yang dimainkan reverb tersendiri dengan durasi yang bergantung pada lama nada ditahan, ukur waktu antara note-on dan note-off, petakan durasi tersebut ke waktu decay, lalu terapkan hasilnya ke reverb khusus untuk nada itu. Biarkan reverb nada tersebut terus berjalan setelah sumber suaranya berhenti.
Tutorial ini membangun perilaku tersebut di SuperCollider, termasuk input MIDI dan pengujian nada yang tumpang tindih. Hasil yang diinginkan sederhana: nada yang ditahan sebentar menghasilkan ekor reverb pendek, sedangkan nada yang ditahan lebih lama menghasilkan ekor yang lebih panjang—bahkan ketika reverb-nya tumpang tindih.
Mengapa setiap nada memerlukan reverb terpisah?
Bayangkan dua nada yang tumpang tindih. Nada pertama ditahan selama dua detik, sedangkan nada kedua ditekan sebentar selama seperempat detik. Jika keduanya masuk ke satu reverb, mengubah decay-nya untuk nada kedua juga mengubah pemrosesan sisa reverberasi nada pertama. Satu kontrol decay bersama tidak dapat mempertahankan dua pengaturan terpisah dalam status reverb yang sama.
Karena itu, peruteannya harus seperti ini: sumber suara setiap nada masuk ke reverb masing-masing, lalu output suara yang sudah diproses dicampur bersama. Ini adalah kesimpulan arsitektural: ekor reverb yang independen memerlukan status pemrosesan yang independen, kecuali instrumen atau efek tersebut sudah menyediakan pemisahan internal yang setara.
Patch polifonik menyediakan kerangka kerja yang berguna untuk ini. Cycling ’74 mendokumentasikan cara poly~ di Max membuat instans suara dan menggunakan thispoly~ untuk menandai setiap instans sebagai sibuk atau tersedia. Untuk tugas ini, suara harus tetap terpakai selama ekor reverb-nya berlangsung, alih-alih langsung tersedia kembali saat note-off. Cycling ’74: Polifoni
Ada juga kendala waktu: selama pertunjukan langsung, durasi akhir nada yang ditahan belum diketahui sampai nada berakhir. Implementasi di bawah menggunakan decay sementara selama tuts ditekan, lalu menetapkan decay terukur saat tuts dilepas. Jika Anda memerlukan decay akhir berlaku sejak awal, gunakan durasi nada yang sudah tersedia dalam sebuah sekuens atau render setiap nada secara terpisah setelahnya.
Apa yang sebaiknya dikendalikan oleh durasi nada ditahan?
Pisahkan tiga kontrol: release amplitudo instrumen, decay reverb, dan level output wet. Release instrumen yang lebih panjang membuat suara terus masuk ke reverb. Level wet yang lebih tinggi membuat efek terdengar lebih keras. Keduanya, dengan sendirinya, tidak membuat decay reverb lebih panjang.
Decay juga biasanya bukan berarti waktu berhenti yang tepat. Dokumentasi Reverb dari Ableton mendefinisikan kontrol Decay sebagai waktu yang diperlukan ekor reverb untuk turun hingga seperseribu amplitudo awalnya, atau −60 dB. Perbedaan ini penting saat membandingkan pengaturan decay dengan saat ekor reverb tak lagi terdengar. Ableton: Referensi Efek Audio Live, Reverb
Untuk implementasi pertama, gunakan pemetaan berikut yang secara eksplisit bersifat ilustratif, dengan semua nilai dalam detik:
decay = min(6.0, max(0.25, 0.25 + 1.5 × heldDuration))
| Durasi ditahan | Decay yang ditetapkan |
|---|---|
| 0.10 detik | 0.40 detik |
| 0.25 detik | 0.625 detik |
| 1.00 detik | 1.75 detik |
| 2.00 detik | 3.25 detik |
| 4.00 detik | 6.00 detik, dibatasi |
Nilai-nilai ini adalah pilihan desain, bukan hasil pengukuran akustik. Nilai minimum memberi ketukan singkat ekor yang terdengar; pengalinya menentukan seberapa kuat lama penekanan mengubah efek; nilai maksimum membatasi decay yang diminta. Mulailah dengan pemetaan ini, lalu sesuaikan ketiga pilihan tersebut sambil menjaga velocity nada dan level wet tetap konstan.
Buat suara yang bertahan setelah note-off
Contoh ini menggunakan GVerb bawaan SuperCollider, yang menerima input mono, menghasilkan dua kanal output, dan menyediakan revtime dalam detik. Dokumentasinya juga menyebut lonjakan penggunaan CPU saat instansiasi dan artefak ketika ukuran ruangan berubah. Karena itu, contoh ini mempertahankan ukuran ruangan tetap dan sebaiknya dicoba terlebih dahulu dengan beberapa nada yang dimainkan bersamaan. SuperCollider: GVerb
Setiap suara mencakup sumber suara kecil dengan dua osilator, release amplitudo singkat, dan satu reverb. Envelop durasi terpisah membebaskan suara hanya setelah jatah waktu untuk ekornya berlalu. EnvGen di SuperCollider mendukung envelop sustain yang dilepas saat gate-nya mencapai nol, serta aksi penyelesaian yang membebaskan synth terkait. SuperCollider: EnvGen
Gunakan sesi SuperCollider baru dengan output audio stereo yang berfungsi. Evaluasi blok penyiapan lengkap berikut, lalu tunggu pesan Held-note reverb ready di jendela Post. Tidak diperlukan sampel atau pustaka tambahan. Kode ini telah ditinjau berdasarkan dokumentasi, tetapi belum dijalankan di sini karena interpreter SuperCollider tidak tersedia.
(
s.waitForBoot {
SynthDef(\heldNoteVerb, {
|out = 0, freq = 440, amp = 0.035,
gate = 1, decay = 1, alive = 1|
var sourceEnv, lifetime, source, wet;
sourceEnv = EnvGen.kr(
Env.asr(0.01, 1, 0.02), gate
);
lifetime = EnvGen.kr(
Env.asr(0.01, 1, 0.03), alive,
doneAction: 2
);
source = (
SinOsc.ar(freq) + (0.25 * SinOsc.ar(freq * 2))
) * amp * sourceEnv;
wet = GVerb.ar(
source,
roomsize: 20,
revtime: Lag.kr(decay, 0.03),
damping: 0.5,
drylevel: 0,
earlyreflevel: 0.2,
taillevel: 0.5
);
Out.ar(out, ((source ! 2) + wet) * lifetime);
}).add;
s.sync;
~heldVoices = Dictionary.new;
~tailJobs = List.new;
~voiceGroup = Group.head(s);
~voiceKey = { |num, chan, src|
src.asString ++ ":" ++ chan.asString ++ ":" ++ num.asString
};
~decayFor = { |held|
(0.25 + (1.5 * held)).clip(0.25, 6.0)
};
~releaseHeld = { |num, chan = 0, src = 0|
var key, queue, entry, held, decay, node;
key = ~voiceKey.value(num, chan, src);
queue = ~heldVoices[key];
if(queue.notNil) {
if(queue.notEmpty) {
entry = queue.removeAt(0);
node = entry[0];
held = (Main.elapsedTime - entry[1]).max(0);
decay = ~decayFor.value(held);
node.set(\decay, decay, \gate, 0);
[\note, num, \held, held, \decay, decay].postln;
~tailJobs.add(Routine {
((2 * decay) + 0.1).wait;
node.set(\alive, 0);
}.play(SystemClock));
};
if(queue.isEmpty) { ~heldVoices.removeAt(key) };
};
};
~startHeld = { |vel, num, chan = 0, src = 0|
var key, node;
if(vel <= 0) {
~releaseHeld.value(num, chan, src);
} {
key = ~voiceKey.value(num, chan, src);
if(~heldVoices[key].isNil) {
~heldVoices[key] = List.new;
};
node = Synth(\heldNoteVerb, [
\freq, num.midicps,
\amp, (vel / 127) * 0.035
], ~voiceGroup);
~heldVoices[key].add([node, Main.elapsedTime]);
};
};
"Held-note reverb ready".postln;
};
)
Urutan saat nada dilepas penting: suara menerima pengaturan decay dan perubahan gate sumber secara bersamaan. Reverb terus memproses sementara sumber memudar selama 20 milidetik. Setelah sekitar dua kali nilai decay yang ditetapkan ditambah sedikit waktu cadangan, seluruh suara memudar lalu membebaskan dirinya sendiri.
Waktu cadangan terakhir itu adalah pilihan pengelolaan sumber daya, bukan hasil pengukuran keheningan. Tambah nilainya jika ekor yang tersisa masih terdengar saat pembersihan. Untuk instrumen yang lebih besar, ganti waktu cadangan tetap dengan pemantauan level output ditambah batas waktu maksimum. Contoh ini juga menyimpan referensi tugas yang sudah selesai sampai pembersihan, jadi ini merupakan demonstrasi, bukan instrumen yang berjalan tanpa batas.
Hubungkan nada MIDI yang dimainkan ke suara yang tepat
Pengukuran durasi terkait dengan suatu instans nada tertentu. Melacak hanya stempel waktu note-on terbaru akan gagal begitu nada mulai tumpang tindih. Penyiapan ini menyimpan setiap suara dan waktu mulainya dengan kunci yang memuat sumber, kanal, dan tinggi nada.
Panduan MIDI SuperCollider menunjukkan cara menginisialisasi MIDI, menghubungkan input, dan menyimpan referensi synth agar note-off dapat melepas suara yang tepat. Referensi MIDIdef menetapkan urutan argumen callback: nilai, nomor nada, kanal, dan sumber. SuperCollider: Menggunakan MIDI, SuperCollider: MIDIdef
Setelah penyiapan menampilkan status siap, evaluasi blok ini untuk memainkan instrumen dari input MIDI yang terhubung:
(
MIDIClient.init;
MIDIIn.connectAll;
MIDIdef.noteOn(\heldVerbOn, { |vel, num, chan, src|
~startHeld.value(vel, num, chan, src);
});
MIDIdef.noteOff(\heldVerbOff, { |vel, num, chan, src|
~releaseHeld.value(num, chan, src);
});
)
Contoh ini mendefinisikan durasi “ditahan” sebagai interval antara peristiwa nada yang diterima. Contoh ini tidak menerapkan perilaku pedal sustain. Jika Anda ingin durasi diperpanjang oleh pedal, tunda operasi pelepasan yang terpengaruh sampai pedal diangkat, lalu ukur interval yang lebih panjang tersebut.
Tekanan berulang pada nada yang sama disimpan dalam antrean dan dilepas mulai dari yang paling lama ditekan. Ini adalah kebijakan pencocokan eksplisit untuk peristiwa nada yang sama dan tumpang tindih pada satu sumber dan kanal. Note-off tanpa pasangan tidak melakukan apa pun; note-on tanpa pasangan tetap aktif sampai pembersihan. Periksa pasangan peristiwa sebelum memperluas instrumen.
Uji ekor reverb yang tumpang tindih sebelum mengubah suara
Uji perilakunya terlebih dahulu tanpa keyboard. Sekuens berikut menggunakan fungsi peristiwa yang sama dengan input MIDI: nada 60 berlangsung selama dua detik, sedangkan nada 67 dimulai saat nada pertama baru berjalan separuh dan berlangsung selama seperempat detik. Decay yang ditetapkan untuk keduanya diperkirakan sekitar 3.25 dan 0.625 detik.
(
~heldTest = Routine {
~startHeld.value(100, 60);
1.0.wait;
~startHeld.value(100, 67);
0.25.wait;
~releaseHeld.value(67);
0.75.wait;
~releaseHeld.value(60);
}.play(SystemClock);
)
SystemClock menyediakan penjadwalan dalam satuan detik, sehingga pengujian ini tidak bergantung pada pengaturan tempo musik. Dalam penggunaan sebenarnya, dapat terjadi sedikit perbedaan antara durasi yang dicetak dan yang diminta. SuperCollider: SystemClock
Dengarkan ekor pendek nada yang lebih tinggi saat nada yang lebih rendah masih berlangsung, lalu dengarkan ekor nada yang lebih rendah yang lebih panjang. Setelah itu, balik durasinya. Pengujian kedua ini membantu memastikan bahwa durasi, bukan tinggi nada, yang mengendalikan hasilnya. Baca pasangan durasi ditahan dan decay yang dicetak sambil mendengarkan audionya.
Untuk menghentikan dan menghapus contoh ini, evaluasi blok pembersihan berikut setelah memasang handler MIDI. Blok ini juga membatalkan tugas ekor reverb yang masih tertunda sebelum menghapus suaranya:
(
MIDIdef(\heldVerbOn).free;
MIDIdef(\heldVerbOff).free;
if(~heldTest.notNil) { ~heldTest.stop };
~tailJobs.do { |job| job.stop };
~tailJobs.clear;
~voiceGroup.free;
~heldVoices.clear;
)
Bagaimana mendiagnosis ekor reverb yang berperilaku keliru?
Jika setiap ekor reverb berubah saat satu nada dilepas, periksa perutean audionya. Stempel waktu per nada tetap menghasilkan perilaku bersama jika hasilnya mengendalikan satu reverb setelah campuran suara. Pindahkan reverb ke dalam setiap suara, atau rutekan audio tiap nada secara terpisah ke instans pemrosesan tersendiri.
Jika ekor reverb menghilang tepat saat note-off, periksa durasi hidup suara. Envelop amplitudo seharusnya menghentikan sumber suara tanpa membebaskan reverb yang menampung sumber tersebut. Dalam implementasi Max, pertahankan status sibuk suara sampai output wet-nya selesai, mengikuti model alokasi poly~ yang didokumentasikan. Cycling ’74: Polifoni
Jika angka decay keliru, cetak kunci peristiwa dan stempel waktunya sebelum mengubah reverb. Di Max, blok pembangun waktu yang sesuai adalah timer, yang mengukur waktu berlalu antara peristiwa dan menggunakan milidetik sebagai satuan bawaan. Konversikan satuan secara eksplisit jika tujuan menggunakan detik. Cycling ’74: timer
Jika performa menjadi tidak stabil, kurangi jumlah suara yang berjalan bersamaan dan periksa pilihan reverb sebelum memperluas patch. Demonstrasi ini tidak menetapkan batas jumlah suara, dan setiap nada baru membuat reverb lain. Instrumen produksi memerlukan kebijakan alokasi eksplisit yang memperhitungkan nada yang masih ditahan dan ekor reverb yang masih berbunyi.
Setelah pengujian waktu dan tumpang tindih berhasil, ganti osilator dengan sumber suara per suara yang Anda pilih. Pertahankan urutan yang sama: alokasikan suara, catat waktu mulainya, ukur saat dilepas, tetapkan decay-nya, dan pertahankan reverb sampai ekornya selesai. Urutan ini menjadikan durasi nada ditahan sebagai kontrol permainan yang dapat diulang.
Sumber
- Polifoni — Dokumentasi Cycling ’74
- timer — Referensi Max — Dokumentasi Cycling ’74
- Referensi Efek Audio Live — Panduan Referensi Ableton Live Versi 12
- GVerb — Bantuan SuperCollider
- EnvGen — Bantuan SuperCollider
- Menggunakan MIDI — Bantuan SuperCollider
- MIDIdef — Bantuan SuperCollider
- SystemClock — Bantuan SuperCollider
