lilypond: Переклад темпових позначок із Scheme

Posted on

Lilypond — просто чудова система набору нот. Якщо вам подобається LaTeX для текстових (і не тільки) документів, вам обов’язково сподобається Lilypond — щойно у вас виникне потреба набрати двійко нот чи ж там оперу (якщо ж ви не знаєте, що таке LaTeX — у вас ще все попереду, я за вас радий!-).

Одна з головних, якщо не найголовніша, переваг Lilypond — можливість інтегрування у нотні документи фрагментів, написаних на Scheme: для визначення макросів, для програмування… чого завгодно, власне. Наприклад, ви можете зображувати «альтеровані» ноти різними кольорами, міняти розмір нот залежно від висоти звучання, чи робити корисніші речі — наприклад, визначати певні правила розставляння нагадувальних значків альтерації, створювати «шаблони» для текстових позначок, керувати з’єднанням восьмушок перекладинами тощо, тощо, тощо (моєї фантазії замало навіть для достойних прикладів).

У цій статті і покажу, як я керую перекладанням темпових позначок (Allegro, Moderato, Leggiero e calmo) з італійської на українську.

Постановка задачі

А саме: наприклад, ми готуємо нотну збірку сторінок на двісті, і ми ще самі не знаємо, чи хочемо бачити темпові позначки італійською чи українською. Крім того, ми продовжуємо дискутувати із «зубрами» щодо української термінології, тож усе може помінятися у будь-який момент. Тож нам треба мати засіб, за допомогою якого можна досить просто всі текстові позначки «перекласти» на українську мову, а чи ж залишити італійськими.

Стратегія

Починаючи з версії 2.11.65, здається, команда Lilypond для вставки темпової позначки як аргумент приймає також markup:

% все це — можливі варіанти команди \tempo:
\tempo "Allegro"
\tempo 4 = 120
\tempo "Moderato" 4 = 60
\tempo \markup { \italic Faster } 4 = 132

Ми створимо функцію, яка повертає markup, і будемо використовувати її таким чином:

% наші ноти:
{
  \tempo \markup { \ukr #"Allegro" }
  c4 c c c
}

Реалізація

Створимо «словник» як список пар:

#(define tempi
  '(
    ("Adagio" . "Повільно")
    ("Allegro" . "Швидко")
    ; і так далі....  
  ))

Наша функція буде дуже простою, ми одразу ж можемо її записати (саме таким чином у Lilypond визначаються функції, які повертають markup):

#(define-markup-command (ukr layout props word) (string?)
  (interpret-markup layout props
    (markup (getLocalized tempi word))))

Тобто, зараз ще допишемо функцію getLocalized, яка братиме аргументи «словник» та «слово, яке треба перекласти».

Ця функція також буде дуже простою:

#(define (getLocalized items word)
  (if (equal? '() items)
      word
      (if (equal? (car (car items)) word)
          (cdr (car items))
          (getLocalized (cdr items) word))))))

Тобто: якщо «словник» уже порожній (дісталися кінця), то вертаємо неперекладене «слово». Якщо ж ні, то порівнюємо «слово» з першим елементом пари і вертаємо другий елемент, якщо вони збігаються. Інакше ж рекурсиво викликаємо себе ж із коротшим словником.

Додаткові можливості

Це все добре, але ми, дивлячись на зверстану збірку, не зрозуміємо, чи бачимо неперекладений термін з причини неповного словника, чи переклад просто вимкнений? До речі, якщо ми захочемо залишити італійські терміни, то нам треба якось вимкнути переклад. Отже, нам треба дещо модифікувати код. Додамо «прапорці» та функції для таких застосувань: «чи треба перекладати», «чи треба позначати неперекладені терміни» та «чи треба позначати перекладені терміни»:

%
% ukr.lyi
%

% чи треба перекладати:
doLocalizeTempo = ##t
% чи позначати (якимось чином — див. нижче) неперекладені терміни:
doMarkUntransTempo = ##t
% чи позначати перекладені терміни:
doMarkTransTempo = ##t

#(define tempi
  '(
    ("Adagio" . "Повільно")
    ("Allegro" . "Швидко")
    ; і так далі....  
  ))

% позначаємо перекладене слово —
% перед словом буде трохи піднята крапка:
#(define (markTransTempo word)
  (if (and (equal? #t doMarkTransTempo) (equal? #t doLocalizeTempo))
      (markup #:raise 0.5 "." word)
      word))

% позначаємо неперекладене слово —
% підкреслюємо його:
#(define (markUntransTempo word)
  (if (and (equal? #t doMarkUntransTempo) (equal? #t doLocalizeTempo))
      (markup #:underline word)
      word))

% так шукаємо слово у словнику:
#(define (getLocalized items word)
  (if (equal? '() items)
      (markUntransTempo word)
      (if (equal? (car (car items)) word)
          (markTransTempo (cdr (car items)))
          (getLocalized (cdr items) word))))

#(define-markup-command (ukr layout props word) (string?)
  (interpret-markup layout props
    (markup (if (equal? #t doLocalizeTempo)
                (getLocalized tempi word)
                word))))

Отже, цей код можна використовувати — у всіх нотних фрагментах, що входять до нашої збірки — таким чином:

%
\include "ukr.lyi"

% а далі — ноти, більш чи менш складні:
{
  \tempo \markup { \ukr #"Moderato" }
  c4 c c c
}

Одним рухом ми керуємо перекладанням темпових позначок у всій нотній збірці — це Lilypond. Як його можна не любити?-)

Примітки

  1. Зрозуміло, що якщо нам у певному нотному документі треба «вимкнути» перекладання, ми в цьому документі просто пишемо:

    % чи треба перекладати:
    doLocalizeTempo = ##f
    

    Те саме стосується і «маркування» перекладених та неперекладених термінів.

  2. У розсилці користувачів Lilypond мені радили використовувати assoc-get для вибору потрібної пари із словника, але я ніяк не можу второпати, як тоді просто та зручно робити маркування.
  3. Взагалі, все це може бути не дуже й розумно — я не програміст, не забувайте :-) — але в мене це все «працює».

One Reply to “lilypond: Переклад темпових позначок із Scheme”

Залишити відповідь до Ще один шматочок мого життя | Brownian motion Скасувати відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *

Цей сайт використовує Akismet для зменшення спаму. Дізнайтеся, як обробляються ваші дані коментарів.