در آموزش های قبلی آموزش آردوینو به تولید صدا با آردوینو، تولید تن و پخش ملودی با استفاده از تابع tone پرداختیم. در این قسمت قصد داریم در مورد تولید تنهای صوتی بدون تداخل با PWM و کنترل MIDI صحبت کنیم.
فرض کنید میخواهید از طریق یک بلندگو یا مبدل صوتی دیگر صدا تولید کنید و باید بهجای استفاده از یک timer، تن را بهصورت نرمافزاری تولید کنید؛ برای مثال، زمانی که لازم است از تابع analogWrite روی پایه 3 یا 11 استفاده کنید.
تابع tone که در بخشهای قبلی توضیح داده شد، استفاده آسانی دارد، اما به یک timer سختافزاری نیاز دارد که ممکن است برای کارهای دیگری مانند analogWrite لازم باشد. کد زیر از timer استفاده نمیکند، اما تا زمانی که نت پخش میشود نمیتواند کار دیگری انجام دهد. برخلاف تابع tone آردوینو، تابع playTone که در اینجا توضیح داده شده مسدودکننده است؛ یعنی تا زمانی که پخش نت تمام نشود، بازنمیگردد.
این sketch شش نت را پخش میکند که هرکدام فرکانسی دو برابر یا یک اکتاو بالاتر از نت قبلی دارند. تابع playTone یک تن را برای مدتزمان مشخص روی یک بلندگو یا مبدل Piezo که به یک پایه خروجی دیجیتال و زمین متصل است تولید میکند؛ شکل 1 را ببینید:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
/* * Tone and fade sketch * Plays tones while fading an LED */ byte speakerPin = 9; byte ledPin = 3; void setup() { pinMode(speakerPin, OUTPUT); } void playTone(int period, int duration) { // period is one cycle of tone // duration is how long the pulsing should last in milliseconds int pulse = period / 2; for (long i = 0; i < duration * 1000L; i += period ) { digitalWrite(speakerPin, HIGH); delayMicroseconds(pulse); digitalWrite(speakerPin, LOW); delayMicroseconds(pulse); } } void fadeLED(){ // These two static variables are assigned initial values // only the first time the function is called. static int brightness = 0; static int changeval = 5; analogWrite(ledPin, brightness); // If we've exceeded the limits of analogWrite brightness += changeval; if (brightness >= 255 || brightness <= 0) changeval *= -1; // Change direction delay(2); } void loop() { // a note with period of 15289 is deep C (second lowest C note on piano) for(int period=15289; period >= 477; period=period / 2) // play 6 octaves { playTone(period, 200); // play tone for 200 ms fadeLED(); } } |

شکل1 – اتصالات بلندگو و LED
تابع playTone از دو مقدار period و duration استفاده میکند. متغیر period زمان لازم برای پخش یک چرخه از تن را مشخص میکند. بلندگو به مدت تعداد میکروثانیهای که period مشخص میکند، ابتدا High و سپس Low پالس میشود. حلقه for این پالسها را به تعداد میلیثانیههایی که در آرگومان duration مشخص شده است تکرار میکند.
اگر ترجیح میدهید بهجای period با فرکانس کار کنید، میتوانید از رابطه معکوس بین فرکانس و period استفاده کنید؛ period برابر است با 1 تقسیم بر فرکانس.
مقدار period باید بر حسب میکروثانیه باشد؛ از آنجا که در یک ثانیه 1 میلیون میکروثانیه وجود دارد، period به شکل 1000000L / frequency محاسبه میشود. حرف L در انتهای این عدد به کامپایلر اعلام میکند که محاسبه را با اعداد صحیح long انجام دهد تا مقدار محاسبه از محدوده یک عدد صحیح معمولی فراتر نرود؛ توضیح اعداد صحیح long را در بخش 2.2 ببینید:
|
1 2 3 4 5 |
void playFrequency(int frequency, int duration) { int period = 1000000L / frequency; int pulse = period / 2; |
باقی کد همان کد تابع playTone است:
|
1 2 3 4 5 6 7 8 9 |
for (long i = 0; i < duration * 1000L; i += period ) { digitalWrite(speakerPin, HIGH); delayMicroseconds(pulse); digitalWrite(speakerPin, LOW); delayMicroseconds(pulse); } } |
کد این بخش تا زمانی که پخش یک تن کامل نشود متوقف میماند و نمیتواند پردازش دیگری انجام دهد. با قرار دادن کد تولید صدا در یک interrupt handler میتوان صدا را در پسزمینه، بدون انتظار برای پایان پخش صدا، تولید کرد. کد منبع تابع tone که همراه با Arduino ارائه میشود نشان میدهد که این کار چگونه انجام میشود.
فرض کنید میخواهید یک synthesizer MIDI را با استفاده از Arduino به پخش موسیقی وادار کنید.
برای اتصال به یک دستگاه MIDI به یک فیش یا سوکت DIN پنجپین نیاز دارید. اگر از سوکت استفاده میکنید، برای اتصال آن به دستگاه به یک کابل نیز نیاز خواهید داشت. کانکتور MIDI را با استفاده از یک مقاومت 220 اهم و مطابق شکل 2 به Arduino متصل کنید.

شکل2- اتصالات MIDI
برای آپلود کد روی Arduino باید دستگاه MIDI را قطع کنید، زیرا ممکن است در روند آپلود اختلال ایجاد کند. پس از آپلود اسکچ، یک دستگاه صوتی MIDI را به خروجی Arduino متصل کنید. هر بار که کلید متصل به پایه 2 را فشار دهید، یک گام موسیقی پخش میشود:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
/* * midiOut sketch * Sends MIDI messages to play a scale on a MIDI instrument * each time the switch on pin 2 is pressed */ // these numbers specify which note to play const byte notes[8] = {60, 62, 64, 65, 67, 69, 71, 72}; const int num_notes = sizeof(notes)/ sizeof(notes[0]); const int switchPin = 2; const int ledPin = LED_BUILTIN; void setup() { Serial.begin(31250); pinMode(switchPin, INPUT_PULLUP); pinMode(ledPin, OUTPUT); } void loop() { if (digitalRead(switchPin) == LOW) { for (byte noteNumber = 0; noteNumber < num_notes; noteNumber++) { // Play the note playMidiNote(1, notes[noteNumber], 127); digitalWrite(ledPin, HIGH); delay(70); // Hold the note // Stop playing the note (velocity of 0) playMidiNote(1, notes[noteNumber], 0); digitalWrite(ledPin, HIGH); delay(30); } } } void playMidiNote(byte channel, byte note, byte velocity) { byte midiMessage= 0x90 + (channel - 1); Serial.write(midiMessage); Serial.write(note); Serial.write(velocity); } |
این اسکچ از پایه TX سریال برای ارسال اطلاعات MIDI استفاده میکند. مدار متصل به پایه 1 ممکن است هنگام آپلود کد روی برد تداخل ایجاد کند. هنگام آپلود، سیم متصل به پایه 1 را جدا کنید و پس از پایان آپلود دوباره آن را وصل کنید.
MIDI در ابتدا برای اتصال سازهای موسیقی دیجیتال به یکدیگر استفاده میشد تا یک ساز بتواند ساز دیگر را کنترل کند. مشخصات MIDI اتصالات الکتریکی و پیامهایی را که باید ارسال کنید توصیف میکند.
MIDI درواقع یک اتصال سریال با سرعت غیراستاندارد 31,250 baud است؛ بنابراین Arduino میتواند با استفاده از سختافزار پورت سریال خود و پایههای 0 و 1، پیامهای MIDI را ارسال و دریافت کند. از آنجا که پورت سریال توسط پیامهای MIDI اشغال شده است، نمیتوانید پیامها را در Serial Monitor چاپ کنید؛ بنابراین اسکچ هر بار که یک نت ارسال میکند LED داخلی را روشن میکند.
هر پیام MIDI دستکم از یک بایت تشکیل شده است. این بایت مشخص میکند چه کاری باید انجام شود. برخی فرمانها به اطلاعات دیگری نیاز ندارند، اما بعضی فرمانها برای معنیدار شدن به داده نیاز دارند. پیام این اسکچ note on است که به دو بخش اطلاعات نیاز دارد: اینکه کدام نت باید پخش شود و صدا با چه بلندی نواخته شود. هر دو مقدار در بازه صفر تا 127 قرار دارند.
sketch پورت سریال را با سرعت 31,250 baud مقداردهی اولیه میکند؛ سایر کدهای مخصوص MIDI در تابع playMidiNote قرار دارند:
|
1 2 3 4 5 6 7 8 |
void playMidiNote(byte channel, byte note, byte velocity) { byte midiMessage= 0x90 + (channel - 1); Serial.write(midiMessage); Serial.write(note); Serial.write(velocity); } |
این تابع سه پارامتر میگیرد و با استفاده از اطلاعات channel، اولین بایتی را که باید ارسال شود محاسبه میکند.
اطلاعات MIDI در کانالهای مختلف از 1 تا 16 ارسال میشوند. هر کانال میتواند روی یک ساز متفاوت تنظیم شود، بنابراین میتوان موسیقی چندکاناله پخش کرد. فرمان note on برای پخش صدا ترکیبی از 0x90، یعنی چهار بیت بالایی b1001، است که چهار بیت پایینی آن با اعداد بین b0000 تا b1111 تنظیم میشوند تا کانالهای MIDI را مشخص کنند. این بایت برای نمایش کانالهای 1 تا 16 از مقادیر 0 تا 15 استفاده میکند، بنابراین ابتدا 1 از شماره کانال کم میشود.
سپس مقدار نت و بلندی صدا ارسال میشود. بلندی صدا در MIDI با نام velocity شناخته میشود، زیرا در ابتدا به سرعت حرکت کلید روی صفحهکلید مربوط بود.
دستورهای Serial.write مشخص میکنند که مقادیر باید بهصورت بایت، نه مقدار ASCII، ارسال شوند. از println استفاده نمیشود، زیرا نویسه بازگشت خط بایتهای اضافی و ناخواستهای به سیگنال اضافه میکند.
صدا با ارسال پیامی مشابه، اما با مقدار velocity برابر با 0، خاموش میشود.
این بخش با دستگاههای MIDI دارای کانکتور MIDI in از نوع DIN پنجپین کار میکند. اگر دستگاه MIDI شما تنها یک کانکتور USB دارد، این روش کار نخواهد کرد. این روش بدون سختافزار اضافی، مانند یک مبدل MIDI-to-USB، امکان کنترل برنامههای موسیقی MIDI در حال اجرا روی رایانه را توسط Arduino فراهم نمیکند. با اینکه Arduino یک کانکتور USB دارد، رایانه آن را بهعنوان یک دستگاه سریال شناسایی میکند، نه یک دستگاه MIDI.
سیسوگ با افتخار فضایی برای اشتراک گذاری دانش شماست. برای ما مقاله بنویسید.