हम सिस्टम स्पीकर पर मारियो से संगीत बजाते हैं

मारियो  टिप्पणियाँ

प्रस्तावना


नमस्ते दुनिया!

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

अस्वीकरण


जैसा लिखा है वैसा ही कोड लिखा है। लेखक एक प्रोग्रामिंग जीनियस नहीं है, लेकिन सिर्फ एक छात्र है, लेकिन फिर भी, उसने सबसे पठनीय और समझने योग्य कोड लिखने की कोशिश की। सब कुछ बोरलैंड सी में लिखा गया था और केवल डॉसबॉक्स में परीक्षण किया गया था क्योंकि कोई स्थापित डॉस नहीं है और मैं वास्तव में एक वास्तविक समय घड़ी के साथ खराब नहीं होना चाहता।

2012 में वापसLoiqig पहले से ही एक कूलर संस्करण लिखा था , लेकिन, जैसा कि यह मुझे लग रहा था, सिद्धांत पर थोड़ा ध्यान दिया।

साथ ही, लेखक (यानी, I) के पास 4 साल की संगीत शिक्षा है और वह सोलफेगीओ (संगीत संकेतन) में गरीब था।

सिद्धांत की बिट


बहुत समय पहले, जब इंटेल 8086 प्रोसेसर लोकप्रिय था, और आईबीएम पीसी ने कोई सवाल नहीं उठाया था, इन 8 आईबीएम पीसी और संगत कंप्यूटरों में इंटेल 8253 का उपयोग किया गया था - एक टाइमर और एक अंतराल काउंटर। आधुनिक कंप्यूटरों में, दक्षिण पुल इससे संबंधित है ( स्रोत: विकिपीडिया )।

नमूना इंटेल 8253 पीआईटी तर्क:

इंटेल 8253 का तर्क आरेख। अंजीर।  1

इंटेल 8253 का तर्क आरेख। अंजीर।  2

जैसा कि आप ऊपर की छवि में देख सकते हैं, टाइमर IRQ0 लाइन से जुड़ा है। यह प्रति सेकंड 8h इंटरप्ट 18.2 बार उत्पन्न करता है।

टाइमर में 3 काउंटर (COUNTER0-2) होते हैं, जो एक दूसरे से स्वतंत्र रूप से संचालित होते हैं।

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

प्रत्येक चैनल में 6 ऑपरेटिंग मोड हैं:

  • मोड 0 - टर्मिनल खाता व्यवधान
  • मोड 1 - प्रोग्रामेबल स्टैंडबाय मल्टीवीब्रेटर
  • मोड 2 - पल्स फ्रीक्वेंसी जेनरेटर
  • मोड 3 - मेन्डर जनरेटर
  • मोड 4 - सॉफ्टवेयर-जनित स्ट्रोब
  • मोड 5 - हार्डवेयर-आधारित स्ट्रोब

चलो पहले कारोबार करें


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

प्रत्येक काउंटर (चैनल) को अलग से प्रोग्राम किया गया है। हमने पहले ही तय कर लिया है कि आपको तीसरे का उपयोग करने की आवश्यकता है। जैसा कि आप ऊपर की छवि में देख सकते हैं, स्पीकर OUT आउटपुट से जुड़ा है। उसी समय, यह पोर्ट 61h से जुड़ा है, जिसके साथ हम स्पीकर को नियंत्रित कर सकते हैं। पहला (सबसे कम महत्वपूर्ण) बिट गेट 2 इनपुट से जुड़ा है और यह निर्धारित करता है कि काउंटर काम कर रहा है या नहीं। दूसरा बिट स्पीकर शुरू करता है।

इस सिद्धांत के आधार पर, ध्वनि बजाने के लिए काम का मोर्चा स्पष्ट हो जाता है:

  • हम CLOCK2 को उस आवृत्ति पर प्रोग्राम करते हैं जिसकी हमें आवश्यकता है (उस पर बाद में)
  • स्पीकर को चालू करने के लिए 61h के पहले दो बिट्स का उपयोग करें

चूंकि डिफॉल्ट सिस्टम स्पीकर केवल एक-स्वर ध्वनियां बजा सकता है (अच्छी तरह से, जैसा कि पुराने पुश-बटन फोन पर था, जहां बूमर खेला गया था), हमें प्रत्येक नोट की आवृत्ति प्राप्त करने की आवश्यकता है।

नोट और आवृत्तियों के अनुपात की तालिका


, / , / 2.

हमारे काउंटर के लिए वांछित आवृत्ति सेट करने के लिए, आपको एक निश्चित सूत्र का उपयोग करने की आवश्यकता है: 1193182 / एन हर्ट्ज, जहां 1193182 टाइमर आवृत्ति (1.193182 मेगाहर्ट्ज यदि सही होना है), एन नोट की आवृत्ति है जिसे आपने स्पीकर पर आउटपुट करने का फैसला किया है।

//   
// _freq —  
// _dur —  
// _del —    
void play_sound(int _freq, int _dur, int _del)
{
	outp(0x43, 0xb6); //     2 ()

	int timer_soundFreq = TIMER_FREQUENCY/_freq; //    
                                                    //.
                                                   // TIMER_FREQUENCY = 1193182

	//     
	outp(0x42, timer_delay & 0x00ff); //   
	outp(0x42, (timer_delay & 0xff00) >> 8); //  


	outp(0x61, inp(0x61) | 3); //  


	delay(_dur); //  ,     ,
		    //   

	outp(0x61, inp(0x61) & 0xfc); //  

	delay(_del); //     
}

मुख्य कार्य बहुत सरल है और, स्पष्ट रूप से, खराब रूप से अनुकूलित, लेकिन यह मामले का सार नहीं बदलता है।

int main(int argc, char const *argv[])
{
	for (size_t i = 0; i < N; ++i) // N —  ,  
	{
		play_sound(FREQUENCY[i], DURATION[i], DELAY[i]);
	}
	return 0;
}

तो हमारे mario के बारे में क्या?


हमने सिस्टम गतिकी के माध्यम से ध्वनियाँ बजाना सीखा। ठीक! लेकिन हम मारियो से एक धुन कैसे खेलते हैं?

गूग्लिंग के जादू का उपयोग करके हमें नोट मिलते हैं:

मारियो से शीट संगीत रिंगटोन
.

इसके बाद, आपको संगीत संकेतन का पाठ्यक्रम याद रखना होगा और प्रत्येक नोट लिखना होगा:

लिखित नोट्स और उनका आयाम:
2 — 1/4
2 — 1/4
2 — 1/8
2 — 1/8
2 — 1/4

2 — 1/4
— 1/4

2 — 1/4
— 1/4
— 1/4

— 1/4
— 1/4
() — 1/8
— 1/4

— 1/4
2 — 1/4
2 — 1/4
2 — 1/4
2 — 1/8
2 --1/8

2 — 1/4
2 — 1/8
2 — 1/8
— 1/8

2 — 1/4
()2 — 1/4
()2 — 1/8
()2 — 1/4
()2 — 1/8

() — 1/4
() — 1/4
2 — 1/4
— 1/4
2 — 1/4
2 — 1/4

2 — 1/4
()2 — 1/4
()2 — 1/8
2 — 1/4
2 — 1/4

3 — 1/4
3 — 1/8
3 — 1/4

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

और भी अधिक धैर्य के साथ, हम प्रत्येक नोट को आवृत्तियों में अनुवाद करते हैं और आवृत्तियों और अवधि के सरणियों को इकट्ठा करते हैं:

// Mario -- 43
int FREQUENCY[] = {659.255, 659.255, 659.255, 523.251, 659.255, 783.991, 391.995, 523.251, 391.995, 329.628, 440, 493.883, 466.164, 440, 391.995, 659.255, 783.991, 880, 698.456, 783.991, 659.255, 523.251, 587.33, 987.767, 783.991, 680.255, 698.456, 622.254, 680.255, 415.305, 466.164, 523.251, 440, 523.251, 587.33, 783.991, 739.989, 729.989, 587.33, 659.255, 1046.502, 1046.502, 1046.502};

int DURATION[] = {300, 300, 160, 160, 300, 300, 300, 300, 300, 300, 300, 300, 160, 300, 300, 300, 300, 300, 160, 160, 300, 160, 160, 160, 300, 300, 160, 300, 160, 300, 300, 300, 300, 300, 300, 300, 300, 160, 300, 300, 300, 160, 300};

int DELAY[] = {35, 35, 50, 35, 35, 350, 200, 35, 35, 200, 35, 35, 35, 200, 35, 35, 35, 35, 35, 200, 35, 35, 35, 35, 35, 35, 35, 35, 200, 35, 35, 35, 35, 35, 200, 35, 35, 35, 35, 200, 35, 35, 0};

इस राग में मैंने 43 नोट गिने। यहाँ यह भी ध्यान देने योग्य है कि मैंने कान के पास के दो नोटों के बीच की देरी को चुना। यह मूल की तुलना में थोड़ा धीमा निकला।

निष्कर्ष


अंत में, मैं यह कहना चाहता हूं कि हार्डवेयर के साथ काम करना कभी-कभी उच्च स्तरीय कोड का एक गुच्छा लिखने की तुलना में अधिक दिलचस्प हो जाता है।

अगर कोई अचानक से मेरे मेलोडी को सुधारना चाहता है या अपनी खुद की कुछ लिखना चाहता है, तो आपका टिप्पणी में स्वागत है।

पुनश्च


यदि आप तय करते हैं कि आप सिस्टम की गतिशीलता पर खेलना चाहते हैं और आप संगीत की मूल बातें नहीं जानते हैं, तो स्पॉइलर के तहत आप कुछ संकेत पा सकते हैं।

संगीत के संकेत
. .
.

All Articles