מקלדת מקאמים

שלום חברים! חיג'אז, נהוונד, עג'אם, בייאת, כורד, צבא, ראסט, סיגא, אומר לכם משהו? אלה מקאמים.

מקאמים הם סולמות במוסיקה המזרחית (מזרחית מקורית, לא מה שיש ברדיו). המשמעות של מקאם היא שיש תו אבסולוטי שבו מתחילים את הסולם, וממנו מוגדרים מרווחים עד סוף האוקטבה.

בשונה ממוסיקה מערבית בה יש רק סולמות אפשריים בודדים שאני מכיר לפחות, במוסיקה המזרחית יש בערך שבעים. עוד הבדל גדול הוא שבמוסיקה מערבית המרחק המינימלי בין תווים הוא חצי טון, במוסיקה המזרחית המרחק הוא רבע טון וזו הסיבה שלחלק מהמוסיקה המזרחית יש צליל אופייני כל כך.

כל זה טוב ויפה אבל זה גורם לבעיה. מכיוון שבמוסיקה המערבית אין רבעי טונים וכלי הנגינה שנפוצים בבתים שלנו כמו גיטרה ופסנתר מכוונים לסולמות מערביים, לא ניתן לנגן בהם הרבה מהמוסיקה המזרחית ללא כיוון מחדש אם בכלל. למי שלא גדל על מוסיקה מזרחית, כמוני, קשה לתפוס את ההבדלים בין המקאמים משמיעה בלבד בלי אפשרות לנגן את התווים ולשמוע את הסולמות. לשם כך כתבתי תוכנה שמאפשר לנגן את סולמות המקאמים במקלדת.

בהתחלה חשבתי שכדי שאוכל להגיע לכל טון שאני רוצה, את כל הצלילים אשמיע על פי התדר שלהם ואצור אותם בצורה דינמית. ערכתי קצת מחקר ומצאתי טבלה של תדרי גלי הקול של התווים השונים, ללא רבעים. מה שלא מצאתי היא דרך להשמיע טון על פי תדר בלי להשתמש ב API של Windows. לא נורא, נשתמש בהקלטה של צליל ונשנה אותו על פי הצורך. את שירות השמעת הצלילים נותנת לנו ספריה מקסימה לתכנות משחקים – SFML שמאפשרת בין השאר שינוי גובה הצליל המושמע. את הצליל, שנשמע קצת כמו קסילופון, הורדתי מהאתר Freesound. אני לא מצליח למצוא את הקובץ המדויק באתר. השימוש בSFML פשוט להפתיע. הקוד הבא למשל מתוך התוכנה יוצר חלון, טוען את קובץ הסאונד וטקסט שיכתב על החלון, ומשמיע את הצליל:

// Create the main window
sf::RenderWindow window(sf::VideoMode(800, 600), "Maqam");

sf::SoundBuffer buffer;
buffer.LoadFromFile("piano.wav");

sf::Sound sound;
sound.SetBuffer(buffer);

// Create a graphical text to display
sf::Font font;
if (!font.LoadFromFile("tahoma.ttf"))
    return EXIT_FAILURE;
sf::Text text_pitch("Frequency", font, 50);

sound.Play();

כמו שהזכרתי, בטבלה נמצאים רק תדרי טונים וחצאי טונים, איך מוצאים תדרים של רבעי טונים כאשר ההשתנות אינה ליניארית? כלומר, אי אפשר פשוט לקחת את המספר שנמצא בין שני חצאים ולהחליט שזה רבע, זה לא מדויק. התשובה נעוצה בדרך שבה יצרו את הטבלה. מתחתיה יש קישור לעמוד שמפרט את הנוסחה שבעזרתה אפשר לחשב את התדר של כל תו שרוצים. לקחתי את הנוסחה ושיניתי בה פרט אחד שמחשב רבעים במקום חצאי טונים. בפשטות לוקחים תדר של תו בסיס, במקרה הזה A4 (לה על האוקטבה הרביעית) שהוא 440Hz וסופרים מה המרחק של התו המבוקש, ברבעי טונים, מהתו A4. מציבים את המרחק ב-n בנוסחה הבאה כאשר עבור תוים הנמוכים מ-A4 משתמשים במינוס n:

כך מקבלים את התדר הרצוי ואפשר להשלים את הטבלה.

לכל מקאם, כזכור, יש תדר בסיס ומרחקים מוגדרים בין תו לתו המאפשרים לדעת מאילו תוים בנוי הסולם. כדי למצוא את הנתונים עבור שמונת המקאמים שבחרתי לשים בתוכנה נעזרתי בWikipedia.

בדיעבד הבנתי איך לחשב את כל התדרים הדרושים בזמן ריצה אבל לא עשיתי זאת כך בקוד שלי. שם הכל מוגדר סטטית וגם לזה יש יתרונות. התוספות החדשות של C++11 מאפשרות ליצור std::map ולמלא אותו בזמן יצירתו. אם מעבירים לקומפיילר ++g את הדגל std=c++0x- הוא מקבל ומקמפל את הקוד הבא:

map<string,vector<string>> m =
{
	{"key1"    ,{"value11" ,"value12"}},
	{"key2"    ,{"value21" ,"value22"}}
}

המשמעות היא אתחול פשוט של מבני נתונים גדולים. זה מזכיר קצת שיטות עבודה של שפות סקריפט וזה נוח מאוד.

המבנה הכללי של התוכנה הוא game loop שמאזינה לאירועים, if-else אחד גדול של כל המקשים בפנים, ונגינה של התו הרצוי בעקבות לחיצה. זה עובד טוב :)

כדי לנגן יש צורך שהמקלדת תהיה מכוונת לאנגלית, והמקשים המנגנים הם כל המקשים בהם יש אותיות באנגלית. המקלדת מכילה כמעט 4 אוקטבות. בעזרת המספרים מחליפים בין המקאמים, והמקש A תמיד מייצג את תו הבסיס של כל מקאם.

ככה זה נראה בפעולה:

את התוכנה ל-Windows ניתן להוריד כאן. את קוד המקור ואת הגירסה ללינוקס נפרסם בהמשך כשהפיתוח יהיה קצת יותר מסודר.

קטגוריות: תכנות

פורסם בתאריך 12th דצמבר 2011 ע"י SoleSoul