Gyakorlati alapok

Egy zenei hármashangzat lejátszásának variációi

 

Bevezetés

Matematika

 

Bevezetés

 

www.informatika-programozas.hu - További információk!

Természetesen nem várhatom el, hogy a Java-programozási nyelv iránt érdeklődő egyúttal értsen a zeneelmélethez is, de szerintem érdekes ötvözni a 2 témakört néhány fejezet erejéig. Mivel a jelen fejezet egy zenei akkord belső világáról értekezik, a mélyebben érdeklődők figyelmébe Gitáriskolám Összhangzattan című fejezetcsomagjának alapos tanulmányozását ajánlom.

 

Ebben a fejezetben megnézzük, hogy 1 db 3 hangból álló C-dúr hármashangzatot (C-E-G) elméletileg hányféleképpen tudunk lejátszani 6 húros, standard hangolású gitáron. Rögtön közöljük is a végeredményt: elméletileg 36-féleképpen és ez általánosítható is, azaz érvényes a rendszerből származtatott összes hármashangzatra. Tehát a végeredmény például egy D-moll hármashangzat esetében (D-F-A) elméletileg szintén ugyanaz, 36 db. Az eredmény azonban csak elméleti, közelítő több okból is:

  1. a probléma bonyolultsága miatt nem foglalkozunk azon lehetőséggel, hogy hármashangzatok lejátszásánál 1 húrra 2 hang is kerülhet, következésképpen premisszánk, azaz kiindulópontunk az 1 húron 1 hang,

  2. számításba kéne vennünk a standard hangolású gitár speciális körülményeit is, nevezetesen: mely hármashangzatok "csonkolódnak", vágódnak le a standard alaphangolás miatt (voltaképpen a tükörkép bal oldalán lévő, üres húros hangokról van szó, ezek felülről lefelé haladva: E-A-D-G-H-E):

www.informatika-programozas.hu

 

A 2. lépést sem tesszük meg, mert vele lényegében a szólótechnikában nem jutnánk előrébb, gyakorlati haszna abszolút nincs. Első pillantásra az elméleti megközelítésnek sincs, de majd később látjuk, hogy mégis lehet.

 

Matematika


Kezdjük kis, tudjuk, hogy nagyon népszerű matematikával!

A C-dúr hármashangzat láthatóan 3 elemből áll (C-E-G) és ezeket 6 húron szeretnénk variálgatni. Feltételek megadása nélkül a kombinatorika nevű borzadály ismétléses variáció nevű szörnyedvényébe futunk bele, amely 3 elem variálását jelenti olyan módon, hogy megengedett az elemek ismétlődése. Ekkor a végeredmény 729 db variáció lesz, mert 36 = 729. A teljes, rendkívül olvasmányos lista külön fejezetben tanulmányozható, kezdő és záró variációi így néznek ki:

1.: CCCCCC
2.: CCCCCE
3.: CCCCCG
4.: CCCCEC
5.: CCCCEE

...

725.: GGGGEE
726.: GGGGEG
727.: GGGGGC
728.: GGGGGE
729.: GGGGGG

A világon egyedülálló módon a Pénzes-féle Gitáriskola programozási kódolást (algoritmusokat) is képes alkalmazni bizonyos zeneelméleti problémák megoldására, szemléltetésére. Az alábbi futtatható Java-kód a fenti eredményeket fogja produkálni (a jelen honlapon programozástechnikai magyarázatokra nem térünk ki):

public class Main {
public static void main(String[] args) {
    char[] tomb = new char[]{'C', 'E', 'G'};
    int count = 1;
    for (int i = 0; i <= 2; i++){
        for (int j = 0; j <= 2; j++){
            for (int k = 0; k <= 2; k++){
                for (int l = 0; l <= 2; l++){
                    for (int m = 0; m <= 2; m++){
                        for (int n = 0; n <= 2; n++) {
                            System.out.print(count + ".: " + tomb[i] + tomb[j] + tomb[k] +
                                                                tomb[l] + tomb[m] + tomb[n] + " ");
                            System.out.println();
                            count++;
                            }
                        }
                    }
                }
            }
        }
    }
}
 

Végeredmény:

1.: CCCCCC
2.: CCCCCE
3.: CCCCCG
4.: CCCCEC
5.: CCCCEE

...

725.: GGGGEE
726.: GGGGEG
727.: GGGGGC
728.: GGGGGE
729.: GGGGGG


Mit jelent például az 1. variáció: CCCCCC? 6 db C hangot a gitár 6 különböző húrján, amelyek egymás alá rendezve így néznek ki:

C
C
C
C
C
C

No, ezzel nem mondtunk nagyot és jutottunk előrébb, ráadásul ez bizony nem is hármashangzat!

 

www.informatika-programozas.hu - Ezt most meg kell tanulni!

Valóban, ám vegyük észre, hogy a 729 db teljes variációs készlet potenciálisan tartalmazza az ÖSSZES lehetséges lejátszási mintát, tehát a teljes halmazból kiemelve az egyik speciális részhalmazt keressük.

 

Programozásban jártasak ilyenkor már bólintanak: a teljes lista nem elég, hanem bizonyos feltételek szerint abból szűrnünk kell.

Zeneelméletileg nézve a C-dúr hármashangzat (C-E-G) abban az esetben is hármashangzat marad, ha hangjait különböző sorrendben szólaltatjuk meg. Nézzük meg ennek teljes variációs mennyiségét:

  1. CEG

  2. CGE

  3. ECG

  4. EGC

  5. GCE

  6. GEC

A végeredmény 6, mert 3! = 6. Ez valójában megint kombinatorikai kérdés, annak ismétlés nélküli permutációs változata, ahol 3 elemre 6 lehetséges permutáció létezik úgy, hogy nem megengedett az elemek ismétlődése.

Kétkedők számára jelzem, hogy ezen fejtegetés már valóban zeneelméleti megközelítés, elég csak 1 gyors pillantást vetnünk a gitáron lecsapódó pacsirtamezei C-dúr akkordra, ahol láthatjuk, hogy a legalsó hang nem C alaphang (root - gyökérhang), hanem E (valójában úgynevezett 1. fordítás)...

 

www.informatika-programozas.hu - C-dúr akkord


...az akkordban szereplő hangok sorrendje pedig fizikailag fentről lefelé haladva a következő:


E

C

E

G

C

E

 

Az E hang tehát az akkordban 3-szor is előfordul. Csak jelzem, hogy itt egy klasszikus zenei fül már elkezdene kényeskedni.
 

www.informatika-programozas.hu - Ezt most meg kell tanulni!

Ilyesféle kényszermegoldások a gitár esetében annak szerkezeti, architekturális felépítése miatt szükségesek. Lényegében emiatt az akkordok sokszor nem foghatók le "tiszta" zeneelméleti felépítésükben úgy, amint például zongoránál.

Bár programozástechnikailag megvalósítható, de mi nem fogjuk követni ezt az alapelvet, ugyanis itt a feltételek a következők lennének:

  1. a variációnak mind a 3 hangot tartalmaznia kell,

  2. 1 hang 3-szoros ismétlődése csak 1-szer megengedett.

Ehelyett kissé szigorúbb, de a zeneelmélethez közelebb álló, így akkordügyileg lényegében jobban hangzó feltételeket szabunk:

Ehhez jó kiindulópont az előbb ismertetett variációs végeredmény:

  1. CEG

  2. CGE

  3. ECG

  4. EGC

  5. GCE

  6. GEC

Vegyük észre, hogy ez valójában egy C-dúr hármashangzat teljes, hangismétlődés nélküli variációs listája 3 húros gitár esetében. Ezt kell kiterjesztünk 6 húros gitárra, tehát a sorozatot (vízszintesen) meg kell dupláznunk:

1.: CEGCEG
2.: CEGCGE
3.: CEGECG
4.: CEGEGC
5.: CEGGCE
6.: CEGGEC
7.: CGECEG
8.: CGECGE
9.: CGEECG
10.: CGEEGC
11.: CGEGCE
12.: CGEGEC

A teljes lista pedig:

1.: CEGCEG
2.: CEGCGE
3.: CEGECG
4.: CEGEGC
5.: CEGGCE
6.: CEGGEC
7.: CGECEG
8.: CGECGE
9.: CGEECG
10.: CGEEGC
11.: CGEGCE
12.: CGEGEC
13.: ECGCEG
14.: ECGCGE
15.: ECGECG
16.: ECGEGC
17.: ECGGCE
18.: ECGGEC
19.: EGCCEG
20.: EGCCGE
21.: EGCECG
22.: EGCEGC
23.: EGCGCE
24.: EGCGEC
25.: GCECEG
26.: GCECGE
27.: GCEECG
28.: GCEEGC
29.: GCEGCE
30.: GCEGEC
31.: GECCEG
32.: GECCGE
33.: GECECG
34.: GECEGC
35.: GECGCE
36.: GECGEC

1 hangra így lesz 12 db variáció, 3 hangra pedig összesen 36 db.

Emeljük ki az egyik variációt (GCEGCE) és nézzük meg, hogy miként csapódik ez le a Pénzes-féle gitártükörképen:

 

www.informatika-programozas.hu - C-dúr akkord

 

www.informatika-programozas.hu - Ezt most meg kell tanulni!

Az algoritmikus megközelítés tehát nem a valóságtól (mi esetünkben a zeneelmélettől) elrugaszkodott képződmény, mert sok esetben konkrétan is működőképes, bár az is igaz, hogy sokszor nem. Az azonban bizonyos, hogy aki ezt ilyen módon tudja kezelni, az már képes magát a rendszert is teljes egészében átlátni.

Nézzük meg a feltételes verzió futtatható Java-kódját is:

public class Main {
public static void main(String[] args) {
    char[] tomb = new char[]{'C', 'E', 'G'};
    StringBuffer depotSB = new StringBuffer();
    boolean OK = false;
    int count = 1;
    for (int i = 0; i <= 2; i++){
        for (int j = 0; j <= 2; j++){
            for (int k = 0; k <= 2; k++){
                for (int l = 0; l <= 2; l++){
                    for (int m = 0; m <= 2; m++){
                        for (int n = 0; n <= 2; n++) {
                            depotSB.delete(0, 5);
                            OK = false;
                            depotSB.append(tomb[i]);
                            depotSB.append(tomb[j]);
                            depotSB.append(tomb[k]);
                            depotSB.append(tomb[l]);
                            depotSB.append(tomb[m]);
                            depotSB.append(tomb[n]);
                            OK = checkString(depotSB);
                            if (OK) {
                                System.out.print(count + ".: " + depotSB);
                                System.out.println();
                                depotSB.delete(0, 5);
                                count++;
                                OK = false;
                            }
                            depotSB.delete(0, 5);
                        }
                    }
                }
            }
        }
    }
}

static boolean checkString(StringBuffer depotSB){
    boolean OKall = false;
    boolean OKpart1 = false;
    boolean OKpart2 = false;
    String part1 = "";
    String part2 = "";
    part1 = depotSB.substring(0, 3);
    part2 = depotSB.substring(3, 6);
    if(part1.equals("CEG")
        || part1.equals("CGE")
        || part1.equals("ECG")
        || part1.equals("EGC")
        || part1.equals("GCE")
        || part1.equals("GEC")){
        OKpart1 = true;
    }

    if(part2.equals("CEG")
        || part2.equals("CGE")
        || part2.equals("ECG")
        || part2.equals("EGC")
        || part2.equals("GCE")
        || part2.equals("GEC")){
        OKpart2 = true;
    }

    if(OKpart1 == true && OKpart2 == true){
        OKall = true;
        return OKall;
    }
    return OKall;
    }
}

Végeredmény:

1.: CEGCEG
2.: CEGCGE
3.: CEGECG
4.: CEGEGC
5.: CEGGCE
6.: CEGGEC
7.: CGECEG
8.: CGECGE
9.: CGEECG
10.: CGEEGC
11.: CGEGCE
12.: CGEGEC
13.: ECGCEG
14.: ECGCGE
15.: ECGECG
16.: ECGEGC
17.: ECGGCE
18.: ECGGEC
19.: EGCCEG
20.: EGCCGE
21.: EGCECG
22.: EGCEGC
23.: EGCGCE
24.: EGCGEC
25.: GCECEG
26.: GCECGE
27.: GCEECG
28.: GCEEGC
29.: GCEGCE
30.: GCEGEC
31.: GECCEG
32.: GECCGE
33.: GECECG
34.: GECEGC
35.: GECGCE
36.: GECGEC


További érdekesség, hogy a kíváncsiságképpen kódalkotáskor felkerestem a chatGPT nevű mesterséges intelligenciát is (AI). A teljes, ismétléses variációs kód problémáját azonnal megértette és küldte annak rekurzív implementációját:

import java.util.ArrayList;
import java.util.List;

public class Main {
public static void main(String[] args) {
    List<String> combinations = new ArrayList<>();
    generateCombinations("", 6, combinations);

// Print the combinations
    for (String combination : combinations) {
    System.out.println(combination);
        }
    }

public static void generateCombinations(String prefix, int remaining, List<String> combinations) {
    if (remaining == 0) {
        combinations.add(prefix);
        return;
    }

    generateCombinations(prefix + "C", remaining - 1, combinations);
    generateCombinations(prefix + "E", remaining - 1, combinations);
    generateCombinations(prefix + "G", remaining - 1, combinations);
    }
}


Végeredmény:
CCCCCC
CCCCCE
CCCCCG
CCCCEC
CCCCEE

...

GGGGEE
GGGGEG
GGGGGC
GGGGGE
GGGGGG


Azonban a feltételmegadást már nem értette meg, bár többféle (angol nyelvű) változattal próbálkoztam. (A feltételmegadás szövegét megismételte, de a hozzá csatolt kód rossz volt. Pontosan mint a rossz tanulók dolgozataiban.) Hát itt tart ma az AI. Szerintem még nem kéne beengedni az ajtón...