paint-brush
तार छेड़ना: अर्थ के साथ संगीत को सजीव करने की कलाद्वारा@charnog
322 रीडिंग
322 रीडिंग

तार छेड़ना: अर्थ के साथ संगीत को सजीव करने की कला

द्वारा Denis Gonchar10m2023/10/18
Read on Terminal Reader

बहुत लंबा; पढ़ने के लिए

संगीत के प्रति जुनून को तकनीकी विशेषज्ञता के साथ जोड़ते हुए, यह टुकड़ा पाठकों को एक विशिष्ट विज़ुअल एल्बम वेबसाइट के निर्माण के माध्यम से ले जाता है। पूर्णतावाद और तीव्र निष्पादन के बीच संतुलन पर जोर देते हुए चुनौतियाँ, कोडिंग शॉर्टकट और ओपन ग्राफ़ प्रोटोकॉल की भूमिका पर प्रकाश डाला गया है।
featured image - तार छेड़ना: अर्थ के साथ संगीत को सजीव करने की कला
Denis Gonchar HackerNoon profile picture
0-item

DALL·E 3 द्वारा एल्बम का कवर


इस लेख में, मैं साझा करूंगा कि कैसे मैंने अपना एल्बम ( https://evhaevla.netlify.app/ ) जारी करने के लिए एक सप्ताहांत में एक प्रोजेक्ट बनाया। मैं कोई प्रशिक्षित संगीतकार या कंपोजर नहीं हूं, लेकिन कभी-कभी मेरे दिमाग में धुनें आ जाती हैं। मैंने उन्हें लिख लिया, और फिर कंप्यूटर को उन्हें चलाने दिया।


2021 में, मैंने अपना एल्बम "एवरीबडी इज़ हैप्पी, एवरीवन इज़ लाफिंग" शीर्षक से लॉन्च किया। यह एक अपरिचित "संगीतकार" का एक साधारण एल्बम है - वह मैं हूं।


मैं सिर्फ संगीत में रुचि नहीं रखता; मैं भी एक डेवलपर हूं, हाल ही में मुख्य रूप से फ्रंटएंड कार्य पर ध्यान केंद्रित कर रहा हूं। मैंने सोचा, क्यों न इन दोनों प्यारों को मिला दिया जाए? इसलिए, मैंने अपने एल्बम को दृश्य रूप से प्रस्तुत करने के लिए एक वेबसाइट डिज़ाइन करने का निश्चय किया।


यह आलेख हर तकनीकी विवरण में गहराई से नहीं उतरेगा - यह बहुत लंबा होगा और हर किसी को पसंद नहीं आएगा। इसके बजाय, मैं मुख्य अवधारणाओं और मेरे सामने आने वाली बाधाओं पर प्रकाश डालूँगा। रुचि रखने वालों के लिए, सभी कोड GitHub पर पाए जा सकते हैं।

तस्वीर

मेरा एल्बम पियानो के लिए बनाया गया है, जिससे निर्णय लेना आसान हो जाता है। पियानो कुंजियों पर उतरने वाले आयतों की कल्पना करें। संगीत में रुचि रखने वाले किसी भी व्यक्ति ने YouTube पर इस तरह से नोट्स दर्शाने वाले कई वीडियो देखे होंगे। एक आयत एक कुंजी को छूती है, उसे रोशन करती है, जो नोट पर प्रहार करने के सटीक क्षण का संकेत देती है।


मैं इस दृश्य शैली की उत्पत्ति के बारे में अनिश्चित हूं, लेकिन त्वरित Google खोज से मुख्य रूप से सिंथेसिया के स्क्रीनशॉट मिलते हैं।

सिंथेसिया यूआई

YouTube पर, ऐसे निर्माता हैं जो दृश्यात्मक रूप से आश्चर्यजनक प्रभाव उत्पन्न करने का प्रबंधन करते हैं। ऐसे वीडियो देखना सौंदर्य और संगीत दोनों ही दृष्टिकोण से एक आनंददायक अनुभव है। इसे या इसे देखें.


हमें क्या लागू करने की आवश्यकता होगी?

  1. चांबियाँ
  2. आयत
  3. ऑडियो
  4. एनिमेशन


आइए प्रत्येक बिंदु से निपटें और इन सभी को क्रियान्वित करें।

चांबियाँ

प्रारंभ में, मैंने मान लिया था कि कुंजियाँ लागू करना सबसे बड़ी चुनौती होगी। हालाँकि, एक त्वरित ऑनलाइन खोज से यह कैसे करना है इसके बारे में ढेर सारे उदाहरण और मार्गदर्शिकाएँ सामने आईं। लालित्य के स्पर्श के साथ एक डिज़ाइन का लक्ष्य रखते हुए, मैंने फिलिप ज़ैस्ट्रो द्वारा बनाए गए एक उदाहरण को चुना।


मेरे लिए बस इतना करना बाकी था कि कुंजियों को कई बार दोहराया जाए और नोटों को सरकाने के लिए एक ग्रिड स्थापित किया जाए। मैंने Vue.js को फ्रंटएंड फ्रेमवर्क के रूप में नियोजित किया है, और नीचे घटक कोड है।

 <template> <ul style="transform: translate3d(0, 0, 0)"> <li :id="`key_${OFFSET - 1}`" style="display: none"></li> <template v-for="key in keys" :key="key.number"> <li :class="`${key.color} ${key.name}`" :id="`key_${key.number}`"></li> </template> </ul> </template> <script setup lang="ts"> import { ref } from 'vue' import type { Key } from '@/components/types' const OFFSET = 24 const template = [ { color: 'white', name: 'c' // Do }, { color: 'black', name: 'cs' // Do-diez }, { color: 'white', name: 'd' // Re }, /* ... */ ] const keys = ref<Key[]>([]) for (let i = 0; i < 72; i++) { keys.value.push({ ...template[i % 12], number: i + OFFSET }) } </script>

मैं यह उल्लेख करना चाहूंगा कि मैंने प्रत्येक कुंजी में एक id विशेषता जोड़ी है, जो उनके एनिमेशन शुरू करते समय आवश्यक होगी।

आयत

हालाँकि यह सबसे सरल खंड प्रतीत हो सकता है, लेकिन कुछ चुनौतियाँ स्पष्ट रूप से छिपी हुई हैं।


  1. उतरते सुरों का प्रभाव कैसे पूरा किया जा सकता है?


  2. क्या ऐसी संरचना बनाए रखने की आवश्यकता है जिससे वर्तमान नोटों को पुनः प्राप्त करने के लिए पूछताछ की जा सके?


  3. ऐसे प्रश्नों के परिणामों को प्रस्तुत करने का सबसे अच्छा तरीका क्या है?


प्रत्येक प्रश्न वांछित प्रभाव को निर्बाध रूप से प्राप्त करने में बाधा उत्पन्न करता है।


मैं प्रत्येक प्रश्न पर ज्यादा देर तक नहीं रुकूंगा, बल्कि सीधे उसका पीछा करूंगा। गतिशील दृष्टिकोण से जुड़ी असंख्य चुनौतियों को देखते हुए, ओकाम के रेज़र पर ध्यान देना और एक स्थिर समाधान का विकल्प चुनना बुद्धिमानी है।


यहां बताया गया है कि मैंने इसे कैसे संबोधित किया: मैंने सभी 6215 नोट्स को एक ही विस्तृत कैनवास पर एक साथ प्रस्तुत किया। यह कैनवास overflow: hidden संपत्ति के साथ स्टाइल वाले कंटेनर के भीतर रखा गया है। गिरते नोट्स प्रभाव को प्राप्त करना तो बस इस कंटेनर के scrollTop एनिमेट करने का मामला है।


हालाँकि, एक लंबित प्रश्न बना हुआ है: मैं प्रत्येक नोट के लिए निर्देशांक कैसे प्राप्त करूँ?


सौभाग्य से, मेरे पास एक MIDI फ़ाइल है जहाँ ये सभी नोट्स संग्रहीत हैं, एल्बम का संगीतकार होने के कारण यह एक सुविधा है। इसका उद्देश्य MIDI फ़ाइल से निकाले गए डेटा का उपयोग करके नोट्स को प्रस्तुत करना है।


यह देखते हुए कि MIDI फ़ाइल बाइनरी प्रारूप में है और मेरा इसे स्वयं पार्स करने का कोई इरादा नहीं था, मैंने मिडी-फ़ाइल लाइब्रेरी की मदद ली।


midi-file लाइब्रेरी MIDI फ़ाइलों से कच्चा डेटा निकालने में कुशल है, लेकिन मेरी ज़रूरतों के लिए, यह पर्याप्त नहीं है। मेरा लक्ष्य ऐप के भीतर निर्बाध रेंडरिंग की सुविधा के लिए इस डेटा को अधिक सुलभ और एप्लिकेशन-अनुकूल प्रारूप में बदलना है।


MIDI फ़ाइल में, मैं सामान्य अर्थों में नोट्स से नहीं, बल्कि घटनाओं से निपट रहा हूँ। इन घटनाओं की एक पूरी श्रृंखला है, लेकिन मैं मुख्य रूप से दो प्रकारों पर ध्यान केंद्रित कर रहा हूं: 'नोटऑन', जो कुंजी दबाने पर ट्रिगर होता है, और 'नोटऑफ', जब कुंजी जारी होती है।


'नोटऑन' और 'नोटऑफ़' दोनों ईवेंट क्रमशः उस विशेष नोट संख्या को निर्दिष्ट करते हैं जिसे दबाया या जारी किया गया था। पारंपरिक अर्थों में, MIDI में समय अनुपस्थित है। इसके बजाय, हमारे पास "टिक" हैं। प्रति बीट टिकों की संख्या MIDI फ़ाइल के हेडर में विस्तृत है।

नीला - बीट्स (डिफ़ॉल्ट लंबाई 96 टिक है), लाल - नोट इवेंट


वास्तव में, विचार करने के लिए और भी बहुत कुछ है। एक टेम्पो ट्रैक भी मौजूद है, जिसमें 'सेटटेम्पो' इवेंट शामिल हैं जो प्रक्रिया का अभिन्न अंग हैं, यह देखते हुए कि प्लेबैक के दौरान टेम्पो बदल सकता है। मेरे प्रारंभिक दृष्टिकोण में टेम्पो के साथ संरेखित करने के लिए कंटेनर की scrollTop प्रॉपर्टी की एनीमेशन गति को समायोजित करना शामिल था।


हालाँकि, मुझे जल्द ही एहसास हुआ कि अत्यधिक त्रुटि संचय के कारण यह अपेक्षित परिणाम नहीं देगा। scrollTop एनिमेट करने के लिए 'रैखिक' समय विस्तार अधिक प्रभावी साबित हुआ।


एनीमेशन पहलू को व्यवस्थित करने के बाद भी, गति को अभी भी शामिल करने की आवश्यकता है। मैंने नोट्स के आयतों की लंबाई को स्वयं समायोजित करके इसका समाधान किया। हालांकि इष्टतम समाधान नहीं है (गति में हेरफेर करना आदर्श होगा), इस विधि ने सुचारू संचालन सुनिश्चित किया।


यह समाधान सही नहीं है, इसका मुख्य कारण यह है कि मैं एक टेम्पो ईवेंट को एक नोट ईवेंट के साथ जोड़ता हूं जो इस आधार पर होता है कि उनके पास समान या कम समय है। इसका मतलब यह है कि यदि कोई अन्य टेम्पो घटना तब होती है जब कोई नोट अभी भी चलने की स्थिति में है, तो इसे आसानी से नजरअंदाज कर दिया जाएगा।


यह संभावित रूप से एक त्रुटि उत्पन्न कर सकता है, खासकर यदि कोई नोट बहुत लंबा है और इसके प्लेटाइम के दौरान नाटकीय गति परिवर्तन हो रहा है। यह एक समझौता है. मैंने इस छोटी सी खामी को स्वीकार कर लिया है क्योंकि मेरा ध्यान तीव्र विकास पर है।


ऐसे उदाहरण हैं जहां गति को प्राथमिकता दी जाती है, और हर विवरण में न उलझना अधिक व्यावहारिक है।

नोट के साथ केवल पहला टेम्पो इवेंट जुड़ा हुआ है


इसलिए, हम निम्नलिखित जानकारी से सुसज्जित हैं:


  1. विशिष्ट कुंजी संख्या
  2. कुंजी दबाए जाने का सटीक क्षण
  3. कुंजी जारी होने का सटीक समय
  4. वह तीव्रता या "गति" जिस पर कुंजी दबाई जाती है


इन विवरणों को हाथ में लेकर, मैं प्रत्येक नोट के लिए कैनवास पर सटीक निर्देशांक बता सकता हूँ। कुंजी संख्या X-अक्ष निर्धारित करती है, जबकि कुंजी दबाने की शुरुआत Y-अक्ष है। प्रेस की लंबाई आयत की ऊंचाई तय करती है।


एक मानक div तत्व का उपयोग करके और उसकी स्थिति को 'पूर्ण' पर सेट करके, मैंने सफलतापूर्वक वांछित प्रभाव प्राप्त किया।

यहां आप जिन आयतों का अवलोकन कर रहे हैं वे अनुप्रयुक्त शैलियों वाले सीधे `<div>` तत्व मात्र हैं। वे बिल्कुल एक लंबे कैनवास पर स्थित हैं, जिसे फिर स्क्रॉल किया जाता है


ऑडियो

मेरा इरादा पियानो के लिए सिंथेसाइज़र बनाने का नहीं था, क्योंकि इसमें बहुत समय लग जाता। इसके बजाय, मैंने एक मौजूदा ओजीजी फ़ाइल का उपयोग किया जो पहले ही "रेंडर" हो चुकी थी और ध्वनि लाइब्रेरी के लिए नेटिव इंस्ट्रूमेंट्स की द ग्रैंड्योर का चयन किया।


व्यक्तिगत रूप से, मेरा मानना है कि यह उपलब्ध सर्वोत्तम पियानो वीएसटी उपकरण है।


मैंने परिणामी OGG फ़ाइल को एक मानक ऑडियो तत्व में एम्बेड किया। तब मेरा मुख्य कार्य ऑडियो को मेरे नोट कैनवास के scrollTop एनीमेशन के साथ सिंक्रनाइज़ करना था।

एनिमेशन

इससे पहले कि मैं सिंक्रोनाइज़ेशन से निपट सकूं, एनीमेशन को पहले स्थापित करना होगा। कैनवास एनीमेशन काफी सीधा है - मैं रैखिक इंटरपोलेशन का उपयोग करके scrollTop अनंत मान से शून्य तक एनिमेट करता हूं। इस एनीमेशन की अवधि एल्बम की लंबाई से मेल खाती है।


जब कोई नोट किसी कुंजी पर उतरता है, तो वह कुंजी प्रकाशित हो जाती है। इसका मतलब यह है कि प्रत्येक नोट के अवतरण के लिए, मुझे संबंधित कुंजी को "सक्रिय" करने की आवश्यकता है, और एक बार जब नोट अपना कोर्स पूरा कर लेता है, तो इसे निष्क्रिय कर दें।


कुल 6215 नोटों के साथ, यह 12,430 नोट सक्रियण और निष्क्रियकरण एनिमेशन के बराबर है।


इसके अतिरिक्त, मेरा लक्ष्य उपयोगकर्ताओं को ऑडियो को रिवाइंड करने की क्षमता प्रदान करना था, जिससे वे एल्बम के भीतर कहीं भी नेविगेट कर सकें। ऐसी सुविधा को लागू करने के लिए एक मजबूत समाधान आवश्यक है।


और जब एक भरोसेमंद समाधान की आवश्यकता का सामना करना पड़ता है जो "बस काम करता है", तो मैं हमेशा ग्रीनसॉक एनिमेशन प्लेटफ़ॉर्म पर जाता हूं।


प्रत्येक कुंजी के लिए सभी एनिमेशन बनाने में लगने वाले कोड की मात्रा को देखें। घटकों को एनिमेट करने के लिए id उपयोग करना एकल पृष्ठ अनुप्रयोगों के लिए सर्वोत्तम अभ्यास नहीं है। हालाँकि, यह विधि वास्तव में समय बचाने वाली है। प्रत्येक कुंजी के लिए मेरे द्वारा उल्लिखित id याद है? यहीं पर वे खेल में आते हैं।


 const keysTl = gsap.timeline() notes.value.forEach((note) => { const keySelector = `#note_${note.noteNumber}` keysTl .set(keySelector, KEY_ACTIVE_STATE, note.positionSeconds) .set(keySelector, KEY_INACTIVE_STATE, note.positionSeconds + note.durationSeconds - 0.02) })


सिंक्रोनाइज़ेशन कोड अनिवार्य रूप से ऑडियो और जीएसएपी वैश्विक समयरेखा के बीच घटनाओं के माध्यम से एक कनेक्शन स्थापित करता है।


 audioRef.value?.addEventListener('timeupdate', () => { const time = audioRef.value?.currentTime ?? 0 globalTl.time(time) }) audioRef.value?.addEventListener('play', () => { globalTl.play() }) audioRef.value?.addEventListener('playing', () => { globalTl.play() }) audioRef.value?.addEventListener('waiting', () => { globalTl.pause() }) audioRef.value?.addEventListener('pause', () => { globalTl.pause() })


कैप्शन

जब मुझे काम ख़त्म करने का मन हुआ तो मेरे दिमाग़ में एक दिलचस्प विचार आया। अगर मैं एल्बम में एक अनोखा मोड़ जोड़ दूं तो क्या होगा? यह मूल रूप से मेरी कार्य सूची में नहीं था, लेकिन मुझे लगा कि इस सुविधा के बिना परियोजना वास्तव में चमक नहीं पाएगी। इसलिए, मैंने इसे भी शामिल करना चुना।


हर बार जब मैं किसी ट्रैक में डूब जाता हूं, तो मैं खुद को इसके गहरे अर्थों पर विचार करता हुआ पाता हूं। संगीतकार क्या संदेश देना चाह रहा था? उदाहरण के लिए, लुडोविको ईनाउडी द्वारा "नाइटबुक" के एक खंड पर विचार करें। पियानो बाएं कान में गूंजता है, जबकि तार दाएं कान में गूंजते हैं।


यह दोनों के बीच एक संवाद का माहौल तैयार करता है। ऐसा महसूस होता है मानो पियानो की कुंजियाँ जाँच रही हों: "क्या आप सहमत हैं?" तार सकारात्मक प्रतिक्रिया देते हैं। "क्या यही प्रश्न है?" तार उनकी पुष्टि को प्रतिध्वनित करते हैं। यह क्रम दोनों उपकरणों के अभिसरण के साथ समाप्त होता है, जो एकता और सद्भाव की प्राप्ति का प्रतीक है। क्या यह मंत्रमुग्ध कर देने वाला अनुभव नहीं है?


यह उल्लेख करना अनिवार्य है कि यह पूरी तरह से मेरी व्यक्तिगत व्याख्या है। एक बार, मुझे मिलान में लुडोविको कॉन्सर्ट में भाग लेने का अवसर मिला। प्रदर्शन के बाद, मैंने उनसे संपर्क किया और पूछा कि क्या उनका वास्तव में उस विशेष खंड में संवाद की धारणा को शामिल करने का इरादा था।


उनकी प्रतिक्रिया ज्ञानवर्धक थी: "मैंने इस पर कभी इस तरह विचार नहीं किया, लेकिन आपके पास निश्चित रूप से एक ज्वलंत कल्पना है।"


उस अनुभव से प्रेरणा लेते हुए, मैंने सोचा: क्या होगा यदि मैं उपशीर्षक को शीट संगीत में एकीकृत कर दूं? जैसे-जैसे विशिष्ट खंड चलते हैं, कमेंटरी ऑन-स्क्रीन साकार हो सकती है, जिससे संगीतकार के इरादे के बारे में अंतर्दृष्टि या व्याख्या मिलती है।


यह सुविधा श्रोताओं को "लेखक का वास्तव में क्या मतलब था?" पर एक गहरी समझ या एक नया दृष्टिकोण प्रदान कर सकता है।


यह सौभाग्य की बात है कि मैंने जीएसएपी को अपने एनिमेशन टूल के रूप में चुना। इसने मुझे सहजता से एक और टाइमलाइन को एकीकृत करने की अनुमति दी, विशेष रूप से कमेंटरी को एनिमेट करने का काम सौंपा गया। इस जोड़ ने प्रक्रिया को सुव्यवस्थित कर दिया और मेरे विचार के कार्यान्वयन को बहुत आसान बना दिया।


मुझे HTML मार्कअप के माध्यम से टिप्पणियाँ पेश करने की इच्छा थी। इसे प्राप्त करने के लिए, मैंने एक घटक तैयार किया जो onMounted इवेंट के दौरान एनीमेशन पेश करता है।

 <template> <div :class="$style.comment" ref="commentRef"> <slot></slot> </div> </template> <script setup lang="ts"> /* ... */ onMounted(() => { if (!commentRef.value) return props.timeline .fromTo( commentRef.value, { autoAlpha: 0 }, { autoAlpha: 1, duration: 0.5 }, props.time ? parseTime(props.time) : props.delay ? `+=${props.delay}` : '+=1' ) .to( commentRef.value, { autoAlpha: 0, duration: 0.5 }, props.time ? parseTime(props.time) + props.duration : `+=${props.duration}` ) }) </script>


इस घटक का उपयोग इस प्रकार होगा.

 <template> <div> <Comment time="0:01" :duration="5" :timeline="commentsTl"> <h1>A title for a track</h1> </Comment> <Comment :delay="1" :duration="13" :timeline="commentsTl"> I would like to say... </Comment>

गुणगान

सभी तत्वों के साथ, अगला कदम साइट को होस्ट करना था। मैंने Netlify को चुना। अब, मैं आपको एल्बम का अनुभव लेने और अंतिम प्रस्तुति देखने के लिए आमंत्रित करता हूं।


https://evhaevla.netlify.app


मैं वास्तव में आशा करता हूं कि वहां अन्य पियानो-प्रेमी डेवलपर्स भी हैं, जो अपने एल्बमों को इतने अनूठे तरीके से प्रदर्शित करने के लिए उत्सुक हैं। यदि आप उनमें से एक हैं, तो प्रोजेक्ट को आगे बढ़ाने में संकोच न करें।