Tytułem wstępu

W okolicach świąt 2023 moje zamiłowanie do grania i tworzenia muzyki poskutkowało kupnem cyfrowego pianina. Roland FP-E50 to solidne klawisze z (niestety) niewystarczająco solidną jakością dźwięku. Przyzwyczajony do poziomu, oferowanego przez cyfrowe wtyczki VSTi pokroju Garritan CFX i Ravenscroft 275 postanowiłem w związku z powyższym kupić moduł dźwiękowy pianina, aby jakość dźwięku zbliżyła się do poziomu pianina akustycznego. Mowa o V3 Sound Grand Piano XXL, który służy mi do dzisiaj w tandemie ze wspomnianym pianinem.

Urządzenie oprócz dobrej jakości emulacji zachowania pianina akustycznego posiada szereg wbudowanych barw dodatkowych. Od perkusyjnych i orkiestrowych brzmień, po wokale, akordeony czy dźwięki typowe dla syntezatorów. Ma natomiast jedną, istotną wadę: nie posiada ekranu LCD ani fizycznych przycisków do zmiany banków brzmień. Jedynie poprzez wysyłanie odpowiednich sygnałów MIDI można dokonać wyboru brzmienia na każdym z 16 kanałów MIDI. Podobnie jest zresztą z kontrolą efektów instrumentalnych. Oznaczałoby to dla mnie utknięcie z wydrukowanymi kartkami w poszukiwaniu danej barwy i informacji, jaki bank oraz który program MIDI należy wysłać do urządzenia. Byłem świadomy tych ograniczeń w trakcie zakupu, jednak miałem jasny plan, jak istotnie zwiększyć wartość sprzętu dla moich potrzeb. Tak rozpoczął się stopniowy rozwój aplikacji webowej, trwający ponad rok.

Początki

W pierwszym podejściu nie planowałem, że całość rozrośnie się o istotnie większą ilość funkcji, niż sam wybór brzmień i ustawień efektów. Ten etap został zrealizowany w dość krótkim czasie. Do tego momentu wszystko było względnie liniowe a podstawowa funkcjonalność gotowa (razem z interfejsem) po mniej niż miesiącu. Aplikacja działała od początku jako PWA i była łatwo dostępna z poziomu tabletu na Androidzie oraz na komórce. Część tego czasu poświęciłem na zbudowanie odpowiedniej struktury HTML pod JavaScript, który będzie wysyłać przez Web MIDI sygnały do urządzenia. Sprzęt posiada między innymi wejście USB Host, przez które niemal każdy kontroler MIDI jest w stanie wysłać i odebrać sygnały.

Przejrzałem dostępną dokumentację urządzenia i zgodnie z nią podzieliłem strukturę HTML na kategorie (osobne elementy DOM), w których na sztywno dodałem elementy z atrybutami bank oraz program z dodatkowym opisem słownym - zgodnym z dokumentacją sprzętu. Z punktu widzenia JavaScript było to kilka linijek kodu. Najpierw inicjalizacja MIDI w przeglądarce, potem znalezienie (w DOM) i wysłanie sygnałów bank change oraz program change po kliknięciu na dany preset w interfejsie. Rozwiązało to pierwszy cel mojej aplikacji.

W tym momencie mógłbym zrezygnować z dalszego rozwoju aplikacji. Robiła to, do czego została stworzona. Miałem jednak świadomość, że tak ograniczone wykorzystanie możliwości sprzętu byłoby zmarnowaniem jego potencjału. Stopniowo rozpocząłem dodawanie kolejnych funkcji, związanych zarówno wprost ze sprzętem, poznawaniem teorii muzyki czy pozwalające na szybkie komponowanie (bez tracenia czasu na uruchomienie komputera dla kilku minut gry). Długie ładowanie systemu było zwyczajnie zniechęcające, szczególnie w środku tygodnia, będąc zmęczonym po całym dniu pracy. Chciałem grać od razu, kiedy mam wenę i móc to zachować do dalszej obróbki komputerowej na później.

Obsługa efektów dźwiękowych

V3 Sound Grand Piano XXL poza bankami brzmień zawiera również szereg efektów, które dzięki sygnałom MIDI mogą zmienić brzmienie instrumentu. Dedykowana zakładka "Presety" w mojej aplikacji służy do modyfikacji tych wartości. Kody CC poszczególnych efektów można było uzyskać z dokumentacji sprzętowej (chociaż brakowało w niej wartości domyślnych). Następujące sygnały są obsługiwane z poziomu interfejsu graficznego aplikacji:

  • Modulation (CC 1)
  • Reverb send (CC 91)
  • Chorus send (CC 93)
  • Volume (CC 7)
  • Expression (CC 11)
  • Panorama (CC 10): 63 to centrum, 0 to dźwięk z lewego głośnika, 127 to dźwięk tylko z prawego, a pomiędzy tymi brzegowymi wartościami częściowe brzmienie instrumentu w lewym lub prawym kanale
  • Sustain (CC 64)
  • Sostenuto (CC 66)
  • Soft pedal (CC 67)
  • Portamento (CC 65)
  • Portamento time (CC 5)
  • Portamento control (CC 84)
  • Envelope attack (CC 73)
  • Envelope release (CC 72)
  • Envelope decay (CC 75)
  • Filter resonance (CC 71)
  • Filter cutoff (CC 74)
  • Vibrato rate (CC 76)
  • Vibrato depth (CC 77)
  • Vibrato delay (CC 79)
  • All sound off (CC 120)
  • Reset all controllers (CC 121)
  • All note off (CC 123)

W przypadku wykorzystania kontrolerów typu mikser, podłączonych do huba USB (podłączonego do tabletu), te same efekty można modyfikować zarówno za pomocą suwaków na ekranie tabletu, jak i sprzętowo zewnętrznym kontrolerem. Przypominając: sam moduł nie posiadał dedykowanych pokręteł i suwaków. Bez zewnętrznego urządzenia nie było to wcześniej możliwe. Modyfikacja sprzętowa lub ekranowa zawsze dotyczy efektu na wybranym kanale MIDI. Nie są to globalne efekty. W trakcie zmian przy użyciu kontrolera fizycznego na ekranie aplikacji widoczna jest nazwa ustawianego parametru oraz jego wartość.

Komponowania na żywo - instrumenty współgrające ze sobą

Moduł dźwiękowy (odmiana syntezatora, tylko bez klawiatury) V3 Sound Grand Piano XXL to instrument o wszechstronnych barwach. Posiada nie tylko dźwięki pianin czy fortepianów, ale również gitary akustyczne, flety, klarnety, bębny, skrzypce i wiele innych brzmień. Rozwijając aplikację była to jedna z istotnych cech, by w ogóle zacząć nad nią pracę. Korzystając z doświadczeń z wtyczkami VST do tworzenia dynamicznych barw symfonicznych na PC przeniosłem to do swojego rozwiązania.

Aby umożliwić pracę z wieloma instrumentami jednocześnie wykorzystałem cechy sprzętu oraz samego protokołu MIDI. W tym przypadku miałem do dyspozycji standardowo 16 kanałów MIDI. Oznacza to, przekładając na praktyczne rozwiązanie, że mogłem użyć 16 warstw dźwiękowych do połączenia kilku banków brzmień w spójną całość. Oczywiście: każdy instrument na scenie ma swoje miejsce w kompozycji. Używanie wszystkich na raz na całym zakresie klawiszy spowodowałoby jedynie chaos.

Rozwiązaniem powyższej kwestii było stworzenie odpowiedniego filtrowania dla każdej warstwy (kanału). Pozwala to ustalać, kiedy dana warstwa będzie interpretować sygnały CC Note on/off, wydobywając dźwięk, a kiedy zostaną one zignorowane. W aplikacji dodałem suwaki do filtrowania per kanał MIDI. Odbywa się ono po stronie aplikacji i jest to funkcjonalność niezależna od sprzętu:

  • Zakres klawiatury (od nuty do nuty): pozwolił mi (przykładowo) uzyskać efekt, gdzie bębny są w małym fragmencie najniższych oktaw, granych lewą ręką, skrzypce w centralnych oktawach, a flety czy trójkąty w najwyższych.
  • Vel. play range (minimum i maksimum): pozwala ograniczyć dźwięki, aby grały tylko w określonym przedziale siły nacisku (dynamiki) klawiszy. Przykładowym wykorzystaniem jest granie np. tego samego instrumentu w artykulacji sustain (dłużej utrzymujący się, ciągły dźwięk) przy mniejszej sile nacisku (np. od 0 do 68 na 127 dostępnych wartości), a przy wyższej sile uzyskać artykulację straccatto (z krótszymi dźwiękami).
  • Velocity multiplier oraz Velocity plus: pierwszy parametr mnoży siłę nacisku, jeśli potrzebujemy, aby dźwięk był wyraźniejszy (nawet, gdy siła nacisku jest minimalna) lub mniejszy w przypadku wartości mniejszej niż 1. Drugi dodaje wartość bezwzględną do faktycznej siły nacisku - przydatne, gdy w scenie chcemy, aby tylko część instrumentów reagowała zgodnie z siłą nacisku.
  • Wartość bezwzględna velocity: używana będzie wartość bewzględna dla siły nacisku, a dana warstwa będzie mieć stałą wartość velocity (dla sygnału MIDI note on). Szczególnie przydatne dla brzmień typowych dla syntezatorów analogowych.

Nagrywanie sygnałów MIDI

Jedną z przeszkód, które napotkałem przy praktyce improwizacji na pianinie, była niemożliwość nagrywania sygnałów MIDI bez włączonego peceta. Samo uruchomienie Windows 11 i programów typu DAW, które to umożliwiały to był spory koszt czasowy i działało to zniechęcająco. Z kolei jakość nagrań audio bezpośrednio z pianina Rolanda była daleka od wiarygodnej barwy pianina. Moduł pianina nie dawał jednocześnie żadnej możliwości nagrywania sygnałów MIDI. Potrzebowałem zarówno audio, jak i możliwości skorzystania z MIDI (chociażby po to, by zamienić w przyszłości nagranie na partytury). Tym samym podjąłem decyzję o napisaniu funkcji, pozwalającej mi przechwytywać sygnały MIDI i zapisywać je w przyjaznym do odczytu i obróbki formacie JSON.

Struktura pliku JSON składa się z elementów takich jak "nazwa", "data-czas-nagrania" (przechowuje moment rozpoczęcia nagrywania z godziną), "sygnalyCC". SygnalyCC zawierają w sobie w głównej mierze:

{
    "cc": 128,
   "value": 68,
   "vel": 75,
   "timestamp": 4298
},

oraz informacje o zmianach programu MIDI, efektów czy sygnały dedykowane efektowi sprzętowemu reverb urządzenia BigSky (więcej o tym będzie niżej). Po wciśnięciu przycisku nagrywania wszystko, co jest przetwarzane przez aplikację w celu odegrania dźwięków na kontrolerze V3 Sound Grand Piano XXL jest również zapisywane do pliku JSON na serwerze. Nie zabrakło rzecz jasna funkcji odtwarzania sygnałów z racji, że nie jest to klasyczny format MIDI. Tak zapisane sygnały można wysłać z powrotem po uruchomieniu komputera do programu, w którym można wykorzystać wtyczki VST, imitujące w bardziej naturalny sposób niż samo pianino Rolanda dźwięk fortepianu.

Konkretne korzyści z takiego podejścia to:

  • nagrywam kiedy chcę, od razu - kilka sekund i jestem gotowy do tworzenia, kiedy tylko mam na to ochotę - bez względu na to, czy jest to środek tygodnia, czy weekend (więcej czasu)
  • skupienie na kreatywnym flow, zamiast na technikaliach zapisu
  • eliminacja zniechęcenia do procesu nagrywania. Nie muszę się zastanawiać, czy improwizacja będzie udana, jak ją nazwać (to mogę zrobić potem, zostawiając nazwy robocze), nie robię bałaganu w plikach na dysku

Chociaż nie jest to funkcja innowacyjna, to dzięki temu, że jej używanie zostało uproszczone do "włącz i nagrywaj" ilość improwizacji, jakie zaczęły powstawać wzrosła kilkukrotnie już w pierwszym miesiącu od jej powstania. Nie wyobrażam sobie obecnie mojej aplikacji bez tego. Ta funkcja pozwoliła mi się rozwinąć muzycznie znacznie szybciej. Mogłem usłyszeć efekty od razu po nagraniu i zdecydować, czy chcę zachować utwór. Sam format JSON dzięki swojej czytelności ułatwił pisanie kodu oraz debugowanie. W przypadku zapisu do zwykłego formatu MIDI (mimo jego niewątpliwych zalet ze względu na standard) istniało dużo większe ryzyko, że w przypadku błędów w kodzie nie odzyskam swoich utworów.

Ponadto poruszanie się po obiekcie typu JSON jest wygodne. Nie wymagało to żadnych dodatkowych bibliotek JavaScript. To w przyszłości również okazało się przydatne. Mogłem nadmiarowe sygnały MIDI, wprost związane z modułem dźwiękowym, odseparować i pomijać. Nie były one potrzebne przy przenoszeniu całości do Reapera, którego używam do uzyskania oszlifowanej wersji improwizacji (lekkie wyrównania tempa, usunięcie okazjonalnych pomyłek).

Wyświetlanie tonacji i skal

Zanim zakupiłem moduł dźwiękowy do pianina, który był głównym motorem powstawania aplikacji, poznawałem tajniki lepszej improwizacji i teorii muzyki dzięki osobnej aplikacji webowej mojego autorstwa. Jej funkcja sprowadzała się w dużym uproszczeniu do:

  1. Wyboru tonacji i klucza np. C-dur
  2. Wyświetlenia gamy na wizualizacji dwóch oktaw obok siebie, aby korzystać tylko z pasujących dźwięków i skupić się na procesie gry, zamiast na myśleniu o tym, które dźwięki są podwyższone, a które nie
  3. Po integracji z aplikacją z aplikacją do obsługi modułu: zapis tonacji w trakcie nagrywania sygnałów MIDI (funkcja opisana wyżej).

Ponadto robiąc rozpoznanie utworów w danych tonacjach wzbogaciłem całość o trochę teoretycznych informacji, niezwykle przydatnych w trakcie wybierania tonacji pod improwizowanie:

  • emocje, jakie są charakterystyczne dla tonacji w danym kluczu
  • przykładowe utwory
  • typowe dla tonacji gatunki muzyczne
  • budowa półtonowa
  • pokrewne skale - szczególnie przydatne, jeśli podchodzisz do znajomości teorii muzyki w sposób bardziej matematyczny. Zamiast pamiętać gamę wszystkich tonacji mogę wybrać tonacje pokrewne, nie zmieniając gamy, ale zmieniając emocje, jakie niesie utwór.

Do samej aplikacji dodałem również kilka elementów teorii muzyki. W szczególności chodzi o opis kadencji w teorii muzyki. Jest również opcja wyświetlania tonacji w formie pentatonicznej. Gama jest wtedy złożona z pięciu dźwięków, które mają najmniej dysonansów. Jest to często wykorzystywane przez improwizatorów klawiszowych, chociaż przyznam szczerze: wolę używać pełnej gamy. Jest również prosta wyszukiwarka tonacji po utworach, emocjach i gatunkach.

UX - poprawki graficzne

W pierwszym etapie podświetlania tonacji gamę zaznaczałem poprzez kolorowanie czarnych i białych klawiszy w interfejsie programu. Pomysł, który wydawał się oczywistym wyborem szybko zderzył się z rzeczywistością. Kiedy logiczny układ oktaw na pianinie ma dwa kolory klawiszy, to umysł jest w stanie szybko wyłapać schemat i dostosować się do tonacji. Jeśli w tym układzie zmieniamy kolor czarny na niebieski, by wyróżnić tylko zgodne z tonacją dźwięki - umysł traci punkt odniesienia. Przykładowo: w tonacji h-moll zamalowanie na niebiesko dźwięku F♯ sprawiło, że wzrok reagował wolniej w poszukiwaniu dźwięków tylko z tonacji. Improwizacje na pianinie traciły na płynności. Łatwiej było pomylić dźwięki w trakcie gry. Na szczęście kompromis, połączony z czytelnością, szybko się pojawił. Zamiast zmieniać kolory klawiszy w całości dodałem jako alternatywną opcję (zachowując pierwotną koncepcję w razie zmiany wyboru) wyświetlanie samych stopni skali w formie kółeczek z rzymskimi liczbami. Odpowiadają one stopniom w danej tonacji. Efekt? Rozpoznawanie dźwięku było natychmiastowe, bez opóźnień na analizę układu oktaw. Całość kosztowała mnie minimalną ilość wysiłku, a całkowicie odmieniła sposób użytkowania modułu z tonacjami.

Obsługa presetów modułu pogłosu BigSky

Po miesiącach praktyki gry na pianinie uznałem, że przydatne będzie wzbogacenie zestawu o sprzętowy efekt pogłosu. Wybór padł na BigSky. Urządzenie, w przeciwieństwie do modułu dźwiękowego pianina, posiada ekran LCD. Mimo tego zdecydowałem, że warto zintegrować je do całego ekosystemu sprzętów MIDI. Przeglądając oficjalną dokumentację producenta sprzętu znalazłem informacje, które pozwoliły mi na przełączanie presetów poprzez standardowe sygnały MIDI. Całość była możliwa do zrobienia dzięki połączeniu ze sprzętem MIDI poprzez adapter bluetooth. Sprzętowo są to tylko sygnały zmiany presetów (program change, bank change) oraz sygnał do włączenia/wyłączenia działania efektu (CC 176,  Note 102 i Velocity 0 dla wyłączenia oraz 127 dla włączenia efektu sprzętowego). Na własne potrzeby zrobiłem również wyszukiwanie presetów ze sprzętu po:

  • nazwie
  • silniku (sprzęt oferuje 12 rodzajów pogłosu)
  • długości trwania ogona pogłosu
  • intensywności w miksie
  • podtypie (Normalny, Echo, Reverse, Chór, Tremolo, Długi atak, Detune\resynth)
  • czy jest w ulubionych.

Ze względu na ograniczenia sprzętowe możliwa jest wyłącznie ręczna integracja tych elementów. Sprzęt nie zwraca zapisanych w urządzeniu nazw presetów, ani innych informacji. Ode mnie zależy, czy tworząc na nim nowe ustawienia reverb, wyrównam to także po stronie aplikacji. Ostatecznie nie jest to jednak istotna przeszkoda. Zrobiłem kilkadziesiąt własnych ustawień oraz skorzystałem z licznych ustawień fabrycznych sprzętu i to było w pełni wystarczające na potrzeby wzbogacenia barwy pianina lub syntezatora.

Wybór presetów, tonacji i jej cech na jednym ekranie

Po dodaniu obsługi sprzętowego pogłosu BigSky doszedłem do wniosku, że potrzebuję innej reprezentacji dostępnych opcji w momencie, gdy tworzę improwizacje na pianinie oraz innej, kiedy tworzę presety z innych banków brzmień. Na tym etapie nie było już miejsca na dodawanie więcej rzeczy w ramach istniejących ekranów tak, aby nie zmusić do przewijania aplikacji w pionie. Jedynym, racjonalnym wyjściem było zrobienie alternatywnego widoku, który jest w efekcie najczęściej wykorzystywaną zakładką w mojej aplikacji.

Wykorzystałem część elementów dostępnych na zakładkach presety, efekty, nagrania i skale do zrobienia skondensowanego widoku ich zawartości. Z presetów zostawiłem tylko wybór zapisanych (w tym efektów reverb BigSky), również z podziałem na kategorie. Ze skal zachowałem wybór skali i toniki oraz przełącznik na wersję pentatoniczną. Z zakładki, która służyła do nagrywania i odtwarzania utworów zachowałem przycisk nagraj/zatrzymaj nagrywanie (przy czym po skończeniu trafiamy na zakładkę nagrania, bo jest to najbardziej intuicyjne).

Widok powstawał z myślą, że ma jak najbardziej pobudzać kreatywność, bez elementów rozpraszających uwagę. W związku z tym do każdej tonacji durowej i molowej dodałem ilustracje, które najbardziej kojarzyły mi się z ich przeznaczeniem.

Trening słuchu absolutnego

Umiejętność rozpoznawania dźwięków ze słuchu w kontekście danej tonacji jest zdecydowanie przydatna w codziennych improwizacjach klawiszowych. Nikt nie chce, by kreatywny bieg gry został zakłócony przez niepasujące brzmienie. Zrobiłem szybkie rozpoznanie i znalazłem aplikację na Androida, która realizuje ten cel. Była bardzo dobra, ale ze względu na jej charakter - potrzebowałem czegoś bardziej pod siebie. Chciałem ćwiczyć rozpoznawanie dźwięków mając brzmienie, które realnie słyszę w trakcie gry. Chciałem również zintegrować ją z możliwością odpowiedzi za pomocą klawiszy. Tylko tyle i aż tyle. Napisanie fragmentu kodu, który za to odpowiadał zajęło w efekcie około 2 dni razem z elementami interfejsu i testami.

Całość pozwala stopniować poziom skomplikowania i filtrować, w którym zakresie dźwięków padają pytania. Elementami filtrów są między innymi:

  • zakres oktaw (i to, czy uwzględniać je w odpowiedzi, czy tez samą nazwę dźwięku)
  • rodzaj klawiszy (np. same białe, same czarne czy też zakres chromatyczny)
  • możliwość zwiększenia częstotliwości pojawiania się tych dźwięków, przy których częściej padały błędne odpowiedzi w ostatnim czasie.

Opcji filtrowania i ustawień quizu jest więcej i pewnie w przyszłości będzie ich przybywać (np. rozpoznanie akordów, ich przewrotów itp.), jednak ważniejsze jest tutaj ogólne przestawienie celu. Efekt był odczuwalny po kilku próbach. Statystyczna poprawność rozpoznawania dźwięków na skali chromatycznej wzrosła do 70-80% w trakcie treningów i generalnie nie spadała poniżej 50%. Nawet 50% przy szansie 1 na 12 "przypadkowego trafienia" to wciąż dużo - znacznie powyżej błędu statystycznego i przypadku.

Partytury

Ta zakładka jest efektem zmiany podejścia do samej gry na pianinie. Częściej niż początkowo korzystam z nut i poznaję istniejące kompozycje (w szczególności ich budowę, niekoniecznie dłuższe sekwencje taktów). W tej sekcji kilka rzeczy interfejsowo i UXowo wykorzystałem, aby sama zakładka miała jak największy sens. Dodałem więc:

  • Odczyt pdf z partyturami oraz ich obróbka w taki sposób, aby plik pdf jak najbardziej wypełniał ekran małego tabletu. Rozróżnianie miejsc, które należy wyciąć zostało zrobione dzięki temu, że minimalna wysokość pięciolinii i wszelkiej maści znaków była dość przewidywalna. Wystarczyło znaleźć fragmenty pdf, które są zbyt krótkie na to, by mogły być częścią pięciolinii (np. numeracje stron)
  • Odczyt tonacji: zapisany w JSON razem ze źródłem ściąganego do wyświetlenia pliku pdf
  • Odczyt BPM: dodany jeszcze przed powstaniem wbudowanego w aplikację własnego metronumu. Na początkowym etapie pomagał mi skonfigurować BPM w aplikacji mobilnej. Obecnie ta wartość jest ustawiana w metronomie aplikacji webowej, co jest oszczędnością czasu przy nauce kilku utworów jednocześnie. Metrum również jest przy tym uwzględniane i również zapisane jako wartość licznik i mianownik w tej samej zmiennej JSON.
  • Prosty filtr: aby w przyszłości przy bardzo długiej liście partytur móc szybciej znaleźć tę właściwą na podstawie nazwy, tonacji poziomu trudności czy rodzaju skali.

Interfejs ma możliwość zwijania listy utworów, aby wyświetlane nuty jak najbardziej wypełniały przestrzeń w poziomie. Ponadto z użytecznych rozwiązań kółko Pitch Bend w tej konkretnej zakładce pozwala na przewijanie partytur, bez sięgania do ekranu tabletu. Bez większego problemu można byłoby tym samym na poziomie sprzętu ustalić inny sygnał MIDI dla wybranego pedału pianina lub ustawić sygnał wychodzący pedału ekspresji. Bez odrywania rąk w trakcie nauki, bez przerywania gry, bez ryzyka strącenia tabletu z aplikacją na pulpicie do nut samego pianina z powodu szybkiej próby przewijania. W późniejszym etapie również i na tej zakładce pojawia się klucz wiolinowy oraz klucz basowy, na którym zależnie od granego dźwięku widzimy podgląd nuty. Jeśli ktoś jest na początku swojej drogi z odczytywania partytur, to jest to nieocenione ułatwienie do korekcji swoich pomyłek. Łatwiej grać z nut, gdy podchodzimy do kolejnych dźwięków relatywnie (np. "następny dźwięk jest o 2 stopnie skali wyżej" zamiast "następny dźwięk to E5"). Takie małe wsparcie wizualne pomaga w sposób wyraźny, o czym będzie niżej.

Zamiana dźwięków na obraz z pięciolinii - klucz wiolinowy i basowy

Przyszedł moment, w którym uznałem, że warto się nauczyć kilku utworów. Pomimo tego, że znałem najważniejsze elementy teorii muzyki potrzebne do improwizowania, to czytanie nut nadal stanowiło pewne wyzwanie. Na początkowym etapie zawsze problemem jest konieczność "liczenia linii". Ponadto ten sam dźwięk może pojawić się w kluczu wiolinowym i basowym, do tego w innym miejscu zależnie od klucza i oktawy. To nie ułatwia nauki.

Celem stworzenia modułu do wyświetlania aktualnego dźwięku z pianina w formie zapisu na kluczu wiolinowym/basowym było wyeliminowanie opóźnień, wynikających z liczenia. Pamięć mięśniowa, w połączeniu z obrazem na ekranie, rzeczywiście istotnie ułatwiła mi w efekcie czytanie partytur. W obecnej postaci moduł ogranicza się tylko do ostatniego dźwięku. Nie pokaże akordów, nie pokaże innych dźwięków z klucza wiolinowego i z klucza basowego. To jednak wystarcza, by znaleźć dźwięk bazowy, a jednocześnie szybciej zapamiętać, które znaki chromatyczne są na których liniach i polach danej tonacji.

Moduł celowo został zmodyfikowany pod moje potrzeby. Łatwo mi zapamiętać gamę, trudniej zapamiętać, gdzie dźwięki leżą na obu pięcioliniach w danej gamie. Moduł z tego względu wyświetla zarówno bemole i krzyżyki przy samym kluczu, jak i bezpośrednio przy danych nutach. Przykładowo: w h-moll podwyższony jest dźwięk C do C♯ oraz F do F♯. Wciśnięcie F♯ spowoduje, że w tym przypadku zobaczymy krzyżyk również przy nucie aby podkreślić, że dźwięk należy do tej tonacji. Gdybym na klawiszach wcisnął dźwięk C lub F, to przy tych dźwiękach pojawiłby się kasownik, wskazujący wyjście z tonacji. W przypadku C-dur i a-moll nie będzie żadnych znaków chromatycznych, o ile nie zostanie wciśnięty klawisz czarny.

Czy cel został zrealizowany? Zdecydowanie. Zauważyłem, że tempo czytania nut poprawiło się po kilku dniach używania. Istniał natomiast problem, który nie został w pierwszym etapie rozwiązany: gdzie wyświetlać te podpowiedzi, aby nie zabierać przestrzeni na inne elementy.

Przełącznik modułów

Problemem z nowym modułem do wyświetlania granych dźwięków na pięciolinii było to, że brakowało już miejsca na jego dodanie, bez poświęcenia obsługi aplikacji z wyłączeniem przewijania jej w pionie. Kolejne miesiące korzystania z niej pozwoliły mi nabyć praktyczne doświadczenie, że nie wszystko wykorzystuję w równym stopniu cały czas. Rzadziej przełączam ustawienia efektu reverb z urządzenia BigSky. Rzadziej też zwracam uwagę na ilustracje do danych tonacji, bo wiele z nich po prostu zapamiętałem w kontekście ich muzycznych właściwości.

Mając świadomość tego zamiast dodawać kolejną zakładkę z innym zestawem modułów przerobiłem istniejącą zakładkę zbiorczą. Moduł do przełączenia efektu reverb osadziłem w kontenerze do podmiany jego zawartości na moduł wyświetlający nuty. Przycisk "Zmień moduł" pozwala w określonych sekcjach na wymianę zawartości ekranu. Ustawienia są zapisywane w local storage, aby całej operacji nie powtarzać przy każdym uruchomieniu aplikacji PWA.

Nazwy akordów na żywo

W ramach rozszerzania wiedzy muzycznej dodałem zamianę zestawu dźwięków na nazwy akordów. Nazwy wyświetlane są w widoku ogólnym jako overlay nad obrazkiem. W ten sposób mogłem zaoszczędzić miejsce, nie poświęcając przy tym użyteczności ilustracji. Ze względu na to, że wiele akordów ma różne znaczenie w kontekście muzycznym i danej tonacji, to wyświetlane nazwy uwzględniają również ich alternatywne nazwy. Ponadto obecność odgrywanej oktawy również zaznaczam w ramach tego modułu, aby lepiej dostrzegać akcenty muzyczne utworów.

Metronom pod improwizacje

Chociaż nie brakuje gotowych aplikacji typu metronom na komórki i tablet, to celem powstania modułu było przygotowanie całości zarówno pod improwizacje, jak i partytury pdf. W przeciwieństwie do rozwiązań dostępnych w sklepie Play od Google wprowadziłem kilka mniej oczywistych elementów w ramach tego modułu.

Pierwszym z nich było spięcie nazewnictwa z klasycznych gatunków muzycznych z ich orientacyjnymi wartościami BPM. Bez względu na to, czy mamy do czynienia z polonezem, walcem, polką, czy między innymi salsą - mogę wybrać szybko zarówno metrum, BPM (Beats Per Minute) oraz charakter akcentu rytmicznego. Pomaga to zrozumieć charakterystykę danych gatunków muzycznych, bez sięgania co chwilę do podręcznikowych teorii.

Jeśli chodzi o samo BPM to tutaj też jest kilka ułatwień. W partyturach klasycznych utworów zamiast wartości BPM często widuje się nazwy zwyczajowe np. andante, moderato, allegro. Szukanie za każdym razem precyzyjnej wartości BPM w trakcie korzystania z partytury szybko staje się uciążliwe, dlatego dokonałem mapowania tych nazw na konkretne wartości.

Ponadto w samym module dodałem kilka rodzajów wzorów rytmicznych (patternów). Kilka z nich jest generycznych np. z akcentem na pierwszy dźwięk w takcie i ciszą na pozostałych, z akcentem na pierwszy i innym dźwiękiem na pozostałych. Są również patterny pod konkretne gatunki muzyczne czy też metra.

Niezależnie od wzorów rytmicznych metronom posiada również wzory dźwiękowe. Na nich w szczególności mi zależało. Wiele typowych metronomów działa z natury w sposób rozpraszający. Dźwięki bywają zbyt mocno zaakcentowane, a zmiana głośności nie zawsze pomaga. Tutaj ten problem rozwiązałem poprzez wybranie kompozycji dźwięków, które odpowiadają moim upodobaniom. Korzystając z tego, że moduł pianina posiada także wokale typu (po angielsku) one, two, three, four wykorzystałem je do stworzenia bardziej "ludzkiej" wersji metronomu głosowego. Same wzory dźwiękowe są powiązane z konkretnymi metrum w presetach tego modułu. Można od ręki wygodnie wybrać gatunek np. walc wiedeński i otrzymać zestaw ustawień dla licznika i mianownika metrum, BPM, wzoru rytmicznego i dźwiękowego.

Unikalnym elementem powiązanym z modułem metronomu jest również wykrywanie nie tylko BPM, ale także metrum na podstawie zagranej melodii na klawiaturze fortepianu. Nie znalazłem nic podobnego ani w dedykowanych aplikacjach typu Camtronome, ani w programach muzycznych. Kiedy mam w głowie konkretną melodię pod improwizację, to ostatnią rzeczą, nad którą chcę się zastanawiać jest BPM i metrum. W trakcie grania improwizacji utrzymywanie metrum i BPM odbywa się w sposób naturalny (nieświadomy). To, co dzieje się naturalnie w trakcie gry nie zawsze jest łatwe do świadomego wychwycenia już po nagraniu (celem obróbki zapisanego utworu na komputerze). Mój moduł pozwala na rozwiązanie tej kwestii. Chociaż algorytm rozpoznania metrum i BPM nie jest idealny, to wciąż oszczędza sporo czasu. Zasada jest prosta: wystarczy na klawiszach pianina cyfrowego lub innego kontrolera MIDI zagrać kilka razy melodię, która albo wprost odpowiada melodii z improwizacji, albo jest zgodna z jej metrum i BPM. Jeśli wartości rytmiczne w melodii są równe, a tonika występuje w takcie jednego taktu tylko raz, to algorytm bez problemu poradzi sobie z rozpoznaniem BPM i zasugeruje metrum. Jeśli wartości rytmiczne są zróżnicowane i/lub dźwięk toniki pojawia się więcej niż raz w takcie to konieczne jest zagranie fragmentu tak, aby tonika wyznaczała długość taktu, a wartości rytmiczne były równe. Rozwiązanie ma swoje ograniczenia, ale nadal są to dużo mniejsze niż jakiekolwiek rozwiązanie do poszukiwania BPM i metrum z innych aplikacji. Po zagraniu czterech lub więcej taktów (najlepiej tych samych) BPM i metrum są skutecznie sugerowane.

Metronom posiada ponadto funkcję płynnego przejścia z jednego metrum do innego. Można ustawić przez ile taktów ma się pojawiać odliczanie, zanim nastąpi zmiana metrum. Jeśli mamy w utworze jedno metrum, to jest to sytuacja typowa i prawdopodobnie najczęstsza. Wtedy tej konkretnej funkcji nie potrzebujemy. Improwizacje i utwory, w których metrum jest zmienne wewnątrz utworu są jednak ciekawsze. Wtedy płynne przejście z jednego metrum do drugiego jest szczególnie potrzebne jako część metronomu.

Pod samo improwizowanie dodałem kilka, pasujących do siebie metrum, a całość wzbogaciłem o losowanie spośród nich, aby uzyskać ciekawsze, improwizowane kompozycje. Z ustawień losowań metrum są też dostępne funkcje:

  • Całkowita losowość (w tym możliwość wylosowania tego samego metrum, czyli bez zmian)
  • Powrót do głównego metrum (po zmianie metrum kolejne metrum będzie takie samo jak początkowego).
  • Zawsze inne (losowość ze sprawdzeniem, czy wylosowane metrum jest na pewno inne niż poprzednie)

Losowania metrum odbywają się co określoną ilość taktów. Wszelkie zmiany metrum w momencie, gdy metronom jest już włączony, odbywają się nie wcześniej niż po ukończeniu taktu. Zapobiega to powstawaniu chaotycznych wzorów rytmicznych. Sam metronom oprócz konfigurowalnych dźwięków wyświetla także tiki w taktach poprzez animację wskaźnika na ilustracji, nawiązującej do klasycznych metronomów mechanicznych, oraz poprzez oznaczanie aktualnego kroku w wybranym wzorze rytmicznym. Takie połączenie ułatwia utrzymywanie pożądanego tempa w sposób naturalny.

Wizualizacja odtwarzanych utworów

Ten fragment aplikacji powstał jako małe ułatwienie w powracaniu do nagranych improwizacji i odświeżenie z pamięci, jak powstawało dane brzmienie (melodia). W widoku nagrań dodałem piano roll, które w trakcie odtwarzania utworów pokazuje animację dla danego dźwięku. Całość ma celowo wstawione opóźnienie przy wygaszaniu i pokazaniu aktualnych dźwięków, aby łatwiej było zauważyć zmiany w melodii i aktywnych dźwiękach. Elementy HTML, z których jest stworzone piano roll w aplikacji, mają ponadto gradient, by w trakcie odtwarzania ciemnymi kolorami podkreślić niższe oktawy pianina, a jasnymi wyższe.

Taby okaryny

Moja pasja do muzyki nie skończyła się na instrumentach klawiszowych. Od jakiegoś czasu myślałem o grze na instrumencie dętym. Ostatecznie ze względu na egzotyczny wygląd wybrałem okarynę. Podobnie jak w przypadku pianina bez doświadczenia i wiedzy muzycznej początki są wyzwaniem. Szczególnie problematyczny jest nie do końca oczywisty układ dziurek względem tego, jaki dźwięk wydają. Załączona do instrumentu instrukcja nie pomagała - wszystko w języku chińskim. Uznałem, że trochę sobie ułatwię naukę. Dodałem wyświetlanie dźwięków w postaci tabów (jeśli są w zakresie okaryny) na ekranie tabletu (grając na pianinie cyfrowym). Ilość pracy potrzebnej na ten mały dodatek (z możliwością wyłączenia jego wyświetlania) była niewielka. Wysiłek do realizacji tego w większości związany był z mapowaniem klawiszy na odpowiednie taby i ich wizualizacja. Samego JavaScriptu nie trzeba było prawie wcale dokładać. Inwestycja czasowa była opłacalna.

Refactoring wizualny

Wzrost ilości elementów wymusił na mnie przyjrzenie się interfejsowi z perspektywy czasu. Dokładanie kolejnych elementów wymagało planowania miejsca w sposób, który pozwalałby na maksymalne skondensowanie treści w ramach jednego, pełnego ekranu na tablecie. Przez cały czas cel był jasny: jeśli zestaw potrzebnych funkcji dla danego flow (nagrywanie, tworzenie presetów, granie z partytur i inne) nie mieści się na ekranie, to trzeba dokonać korekt w interfejsie lub zmiany podejścia. Taki refactoring był dokonywany kilka razy wraz ze wzrostem ilości modułów. Zazwyczaj były to relatywnie małe decyzje, czasem zwykłe porządki w kodzie, a czasem istotne zmiany w strukturze interfejsu. Między innymi w czasie jednego z takich refactoringów dodałem wspomniany wcześniej przełącznik modułów w ramach tego samego widoku.

Wyzwania

Problem: urządzenia MIDI nie pozwalają na odczyt aktualnych ustawień
Obsługa urządzeń MIDI nie jest najprzyjemniejszym ani najłatwiejszym zajęciem, jakie można sobie wyobrazić. Trudność jest szczególnie widoczna, gdy trzeba coś zdebugować. Sprzęt przyjmuje sygnały MIDI, ale sam w sobie nie zwraca żadnych wartości. Nie ma możliwości odczytania stanu wprost z urządzenia. Oznacza to w praktyce, ze sterując efektem reverb, chorus, portamento czy jakimkolwiek innym trzeba domyślać się początkowych wartości. W samej dokumentacji nie ma takich informacji.

Brak zwrotnej komunikacji po stronie urządzeń typu moduły dźwiękowe czy syntezatory, to również problem natury technicznej. Dopóki nie zagrasz i nie usłyszysz to nie wiesz, czy seria sygnałów została przetworzona. Pozornie to tylko mała niedogodność, ale trzeba mieć świadomość kilku rzeczy. Tworząc moją aplikację webową moduł własnych presetów to był pomysł, który realnie był wykorzystywane do tworzenia własnych zestawów brzmień i ustawień efektów. W momencie, gdy seria sygnałów MIDI była wysyłana do modułu dźwiękowego pianina nie było gwarancji, że sprzęt na nie zareaguje. Niestety: nie zawsze odpowiadał na nie. Przyczyna tkwiła w samym sprzęcie. Zmieniając zestaw dźwięków i ustawienia efektów dla kilku kanałów osobno syntezator nie wyrabiał się z tym i część sygnałów CC MIDI ignorował.

Rozwiązanie:
Dodałem pewien rodzaj opóźnienia milisekundowego pomiędzy poszczególnymi sygnałami. Działało, ale wpływało jednocześnie na tempo wczytywania całości brzmień przy wyborze z listy. Jako uzupełnienie, które zwiększyło szybkość przetwarzania dołożyłem śledzenie faktycznych zmian między obecnym brzmieniem, a tym zestawem dźwięków i ustawień efektów, który jest odczytywany. Zamiast przetwarzania kilkunastu efektów na warstwę (a samych warstw można mieć do 16), program wysyła sygnały CC MIDI tylko wtedy, gdy między obecnym ustawieniem na danym kanale MIDI danego efektu, a ustawieniem dla kolejnego presetu jest realna różnica.

Problem: wydajność
Na pewnym etapie rozwoju aplikacji w ramach usprawnień UX-owych dodałem wyświetlanie informacji o stanie suwaków (efektów) przy zmianie z zewnętrznego urządzenia sterującego (Launch Control Pro). Operacja, jeśli chodzi o czyste przekazanie zmiany poziomu, jest lekka dla JavaScript. Jeśli jednak każda zmiana ma być wyświetlana w komunikatach ekranowych na overlay, to modyfikacje DOM z taką częstotliwością istotnie zmniejszają responsywność aplikacji. Latencja staje się wtedy odczuwalna, bo aplikacja bezpośrednio uczestniczy w przekazywaniu komunikatów pomiędzy pianinem cyfrowym, a modułem dźwiękowym pianina. Tego rodzaju opóźnienie powodowało, że dźwięk nie grał wtedy, kiedy ja gram.

Rozwiązanie:
Ograniczenie reakcji wizualnej na część sygnałów - szczególnie Modulation, Sustain, Sostenuto i Soft pedal. Był to niewielki kompromis, w zasadzie nieodczuwalny, bo w przypadku tych sygnałów jest to wpisane wprost w grę na pianinie i poziom nacisku poszczególnych pedałów i koła modulacji.

Plany dalszego rozwoju

Im więcej rozumiem teorię muzyki w praktyce, tym bardziej widzę, w jakich kwestiach mam jeszcze braki. Kilka rzeczy zaplanowałem już na przyszłość do swojej aplikacji:

  • Wyświetlanie na pięcioliniach wszystkich granych dźwięków razem (nie tylko ostatniego sygnału), aby widzieć wizualnie również akordy. Będzie to szalenie istotne przy płynnym, natychmiastowym odczycie akordów z nut.
  • Trening idealnego rytmu - metronom już mam, chciałbym jeszcze dołożyć moduł, który ocenia dokładność rytmu na bieżąco oraz dodaje możliwość ćwiczenia wartości rytmicznych, wylosowanych przez aplikację. To pozwoli mi pewniej utrzymywać właściwe tempo.
  • Szybki eksport do MIDI - nie będzie zastępować zapisu JSON, który jest sprawdzony i z wielu względów bezpieczny. Będzie jedynie służyć przyspieszeniu zgrywania materiału do formy ostatecznej. Tutaj raczej posłużę się biblioteką zewnętrzną po rozpoznaniu gotowych rozwiązań.
  • Drukowanie do pdf własnych nagrań jako partytur - przynajmniej uproszczonych. Raczej dalsza przyszłość.
  • Dalszy refactoring kodu - tego nigdy za wiele i wraz z rozrastaniem się aplikacji jest nieuniknione do zapewnienia czytelności JavaScript.