در آموزش های قبلی به تولید تنهای صوتی بدون تداخل با PWM و کنترل MIDI با استفاده از تابع analogWrite پرداختیم. در این قسمت قصد داریم در مورد ساخت یک Synthesizer صوتی و دستیابی به Synthesis صوتی با کیفیت بالا صحبت کنیم.
فرض کنید میخواهید صداهای پیچیدهای مشابه صداهایی که برای تولید موسیقی الکترونیک استفاده میشوند ایجاد کنید.
شبیهسازی نوسانسازهای صوتی که در یک synthesizer صدا استفاده میشوند پیچیده است، اما Peter Knight اسکچی با نام Auduino ساخته است که Arduino را قادر میسازد صداهای پیچیدهتر و جالبتری تولید کند. از آنجا که Auduino از قابلیتهای سطح پایین زیادی استفاده میکند، بعید است روی چیزی غیر از بردهای ۸ بیتی مبتنی بر ATmega مانند Uno اجرا شود.
پنج مقاومت متغیر خطی ۴٫۷ کیلو اهم را مطابق شکل ( 1 ) به پایههای آنالوگ ۰ تا ۴ متصل کنید. مقاومتهای متغیر با محور بزرگ بهتر از presetهای کوچک هستند، زیرا میتوانید تنظیمات را بهراحتی بچرخانید. پایه ۳ برای خروجی صدا استفاده میشود و با استفاده از یک فیش جک به تقویتکننده متصل میشود.
سطح ولتاژ (۵ ولت) بیشتر از چیزی است که تقویتکنندههای صوتی انتظار دارند، بنابراین شاید لازم باشد از یک مقاومت متغیر ۴٫۷ کیلو اهم برای کاهش ولتاژ استفاده کنید (یک سر آن را به پایه ۹ و سر دیگر را به زمین متصل کنید؛ سپس لغزنده را به نوک فیش جک وصل کنید. بدنه فیش جک به زمین متصل میشود).
کد sketch پیچیده است، زیرا مستقیماً timerهای سختافزاری را برای تولید فرکانسهای موردنظر کنترل میکند و این فرکانسها در نرمافزار برای ایجاد جلوههای صوتی تبدیل میشوند. کد در متن آورده نشده است، زیرا برای استفاده از Auduino نیازی به درک آن ندارید.
Auduino از روشی به نام سنتز دانهای (granular synthesis) برای تولید صدا استفاده میکند. این روش از دو منبع صدای تولیدشده بهصورت الکترونیکی استفاده میکند که دانه (grain) نامیده میشوند. مقاومتهای متغیر فرکانس و افت هر دانه را کنترل میکنند؛ ورودیهای ۰ و ۲ برای یک دانه و ورودیهای ۳ و ۱ برای دانه دیگر استفاده میشوند. ورودی ۴ هماهنگسازی بین دانهها را کنترل میکند.

شکل ( 1 ) نمودار سیمکشی برای کنترل و شنیدن Auduino
اگر میخواهید کد را تغییر دهید، میتوانید گام مورد استفاده برای محاسبه فرکانس را عوض کنید. تنظیم پیشفرض پنتاتونیک است، اما میتوانید آن را comment کنید و گزینه دیگری را از حالت comment خارج کنید تا از گام متفاوتی استفاده شود.
هنگام افزودن کد به حلقه اصلی مراقب باشید، زیرا sketch بهشدت بهینه شده است و کد اضافی میتواند سرعت آن را بیش از حد کاهش دهد و باعث شود سنتز صدا بهخوبی کار نکند.
میتوانید هرکدام از مقاومتهای متغیر را با حسگرهایی جایگزین کنید که قادر به تولید سیگنال ولتاژ آنالوگ هستند. برای مثال، یک photoresistor یا یک سنسور فاصله که به یکی از ورودیهای فرکانس، یعنی پایه ۰ یا ۳، متصل شود، به شما امکان میدهد با نزدیک یا دور کردن دست از حسگر، زیر و بمی صدا را کنترل کنید. برای اطلاعات بیشتر درباره این ساز موسیقی که با تشخیص حرکت دست نواخته میشود، عبارت «theremin» را در Wikipedia یا Google جستوجو کنید.
فرض کنید میخواهید صدایی با کیفیت بالاتر از آنچه با کتابخانه Tone روی یک برد ۸ بیتی ممکن است تولید کنید. بردهای ۸ بیتی معمولاً بدون سختافزار اضافی فقط میتوانند سیگنالهای موج مربعی تولید کنند. برای مثال، میخواهید موسیقی را با موجهای سینوسی پخش کنید، فایلهای WAV را پخش کنید یا بدون سختافزار اضافی سنتز صوتی پیشرفته انجام دهید.
همانطور که میدانید، بردهای مبتنی بر SAMD روی یکی از پایههای خود یک مبدل دیجیتال به آنالوگ (DAC) دارند که میتواند ولتاژهای واقعی بین ۰ ولت و ولتاژ کاری برد، یعنی ۳٫۳ ولت، تولید کند. این قابلیت در کنار سرعت بالاتر بردهای ۳۲ بیتی، امکان تولید waveformهای پیچیده را فراهم میکند. برد خود را به یک مبدل صوتی متصل کنید، اما بهجای اتصال مبدل به پایه ۹، از پایه DAC استفاده کنید؛ این پایه در Arduino Zero، Adafruit Metro M0 و SparkFun RedBoard Turbo همان آنالوگ ۰ است.
کتابخانه Mozzi را نصب کنید و sketch زیر را اجرا کنید:
|
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 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
/* * Mozzi Melody * Play the Chimes of Big Ben */ #include <MozziGuts.h> #include <Oscil.h> // oscillator template #include <tables/sin2048_int8.h> // sine table for oscillator #include <EventDelay.h> #include <mozzi_midi.h> #define CONTROL_RATE 64 // Control rate in Hz, use powers of 2 enum notes { E3 = 52, B4 = 59, E4 = 64, F4S = 66, G4S = 68, REST = 0 }; int score[] = { E4, G4S, F4S, B4, REST, E4, F4S, G4S, E4, REST, G4S, E4, F4S, B4, REST, B4, F4S, G4S, E4, REST, E3, REST, E3, REST, E3, REST, E3, REST }; const byte scoreLen = sizeof(score) / sizeof(score[0]); byte beats[scoreLen] = {2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 10, 4, 4, 4, 4, 4, 4, 4, 10}; unsigned int beat_ms = 60000 / 180; // the time in ms for 1/8 note const int pauseTime = 200; // pause between notes int currNote = 0; // index of the note we're playing bool pausing = false; // Mini-rest between beats Oscil <SIN2048_NUM_CELLS, AUDIO_RATE> aSin(SIN2048_DATA); // Sine wave EventDelay kChangeNoteDelay; // Delay object void setup() { startMozzi(CONTROL_RATE); kChangeNoteDelay.start(); } void updateControl() { if (kChangeNoteDelay.ready()) { // Is the delay up? pausing = !pausing; // Toggle rest state if (pausing) { aSin.setFreq(0); // set the frequency kChangeNoteDelay.set(pauseTime); // Hold the rest for 200 ms } else { if (currNote >= scoreLen) { currNote = 0; // Go back to the beginning when done } int duration = beats[currNote] * beat_ms; // get duration from array kChangeNoteDelay.set(duration - pauseTime); // Set the note duration aSin.setFreq(mtof(score[currNote])); // set the frequency currNote++; } kChangeNoteDelay.start(); } } int updateAudio() { return aSin.next(); } void loop() { audioHook(); // You must have this in your loop } |
Mozzi یک کتابخانه پیشرفته سنتز صدا برای Arduino و بردهای سازگار است. اگرچه از بردهای ۸ بیتی پشتیبانی میکند، اما از PWM استفاده میکند؛ بنابراین کیفیت صدا محدود است. اما روی بردهای ۳۲ بیتی مانند بردهای مبتنی بر SAMD و Teensy عملکرد بسیار خوبی دارد. Mozzi یک framework قدرتمند با قابلیتهای فراوان است و دهها برنامه نمونه نیز دارد.
sketch با اضافه کردن فایلهای header Mozzi و تعریف نرخ کنترل Mozzi تنظیم میشود. نرخ کنترل تعیین میکند توابع update چند وقت یکبار فراخوانی شوند. سپس sketch یک enum از نتهای استفادهشده در این sketch تعریف میکند. برای راحتی از نتهای MIDI استفاده شده است. از آنجا که نتهای MIDI میتوانند بهصورت اعداد صحیح نمایش داده شوند، میتوانید آنها را در یک enum استفاده کنید و این موضوع استفاده از نامهای نمادین آنها را در یک آرایه از اعداد صحیح آسان میکند. همین کار را میتوان با #defineها نیز انجام داد که در این صورت میتوانید بهجای شمارههای MIDI از فرکانسهای اعشاری استفاده کنید.
مشابه sketch بخش ۹٫۲، این sketch از یک آرایه برای نمایش پارتیتور و از آرایهای دیگر برای نمایش تعداد ضربهایی که هر نت باید نگه داشته شود استفاده میکند. سپس متغیرها و objectهایی را که بعداً در sketch استفاده میشوند مقداردهی اولیه میکند.
سیسوگ با افتخار فضایی برای اشتراک گذاری دانش شماست. برای ما مقاله بنویسید.