De Parsons code (formeel de Parsons Code for Melodic Contours) is een eenvoudige notatie die gebruikt wordt om muziekfragmenten te identificeren door middel van melodische beweging — de beweging van de toonhoogte naar boven en naar beneden. Denys Parsons ontwikkelde het systeem voor zijn boek The Directory of Tunes and Musical Themes uit 1975. Door een melodie op deze manier voor te stellen, is het een stuk eenvoudiger om naar muziekstukken te zoeken, vooral als de noten niet precies gekend zijn.
In de Parsons code wordt de eerste noot van een melodie voorgesteld door een asterisk (*). Elke volgende noot wordt genoteerd als één van drie mogelijke letters die de relatie van de toonhoogte van de noot aangeven in vergelijking met de voorgaande noot:
de letter U (up) als de noot hoger is dan de vorige noot
de letter D (down) als de noot lager is dan de vorige noot
de letter R (repeat) als de noot dezelfde toonhoogte heeft als de vorige noot
Deze letters worden de bewegingen van de melodie genoemd. Het verschil in toonhoogte tussen twee opeenvolgende noten wordt in deze voorstelling dus genegeerd. Hieronder zie je bijvoorbeeld een grafische voorstelling van de Parsons code *RUURDDDDRUURDR van het thema Ode to Joy1 (originele Duitse titel: An die Freude) uit de Negende Symfonie van Beethoven, dat gebruikt werd als basis voor het Europese volkslied.
* R U U R D D D D R U U R D R
+2 *-*
/ \
+1 * *
/ \
0 *-* * *-*
\ / \
-1 * * *-*
\ /
-2 *-*
Als de toonhoogte van de eerste noot gebruikt wordt als referentieniveau (niveau 0), dan beweegt dit thema zich dus tussen twee niveau's onder (-2) en twee niveau's boven (+2) het referentieniveau. We noemen dit respectievelijk de maximale afwijking naar onder en de maximale afwijking naar boven.
Deze voorstelling blijkt verrassend effectief te zijn. Parsons, die vijf jaar van zijn leven spendeerde aan het indexeren van bijna alle bekende klassieke melodieën vanaf de 16e eeuw, schreef hierover
I continue to be astonished that such a simple test, taken to the sixteenth note (or less), should be adequate to distinguish more than 10.000 classical themes.
Kan je bijvoorbeeld de klassieke melodieën identificeren waarvan de Parsons code hieronder wordt weergeven? Klik hier om het antwoord zichtbaar te maken.
*RUDUDDRUDUD
*RURURDDRDRDRDURDRDRDURDRDRDDRURURDDRDRDRD
*UDDUUDDURDURDURUDDDUDDURUDDDUDDURUDDUUDDDUDDD
*UDUUDUDDDUU
*UDDUUUU
*RRURDDRDRRURDUDURRRRDDRDUUDDRDU
*RDUDUURURDRDDRUDUDUU
*RRDURRD
*RUURURDRDRUURURDR
*DUDUDUUUDDUDUDDUD
*DUDDDDDUDDUDUDU
*UDUUDUDUUDUDUUDUDUU
*DUDUDUDURRRRRRRRDUDU
*RRRRRRRUUUDRRRRUURDDD
We stellen een Parsons code voor als een string (str) die start met een asterisk (*) en die verder enkel de letters U, D en R bevat. Bij een Parsons code wordt geen onderscheid gemaakt tussen hoofdletters en kleine letters.
Een contourplot is een grafische voorstelling van een Parsons code in de vorm van een rechthoekig rooster. Hieronder zie je bijvoorbeeld de contourplot van de Parsons code *RUURDDDDRUURDR, waarbij de lege cellen spaties voorstellen.
De toonhoogte van de eerste noot wordt in de eerste kolom aangegeven met een asterisk (*). Elke beweging van de Parsons code zet twee bewegingstekens in de volgende twee kolommen van het rooster: bij de letter U worden de tekens / en * telkens een rij hoger gezet, bij de letter D worden de tekens \ en * telkens een rij lager gezet, en bij de letter R worden de tekens - en * telkens op de huidige rij gezet. Het rooster van de contourplot wordt zo gekozen dat de eerste en de laatste kolom respectievelijk corresponderen met de eerste en de laatste noot, en dat de eerste en de laatste rij respectievelijk corresponderen met de maximale afwijking naar boven en naar onder. Gevraagd wordt:
Schrijf een functie maximale_afwijking waaraan een Parsons code (str) moet doorgegeven worden. De functie moet een tuple (tuple) teruggeven met de maximale afwijking naar onder (int) en de maximale afwijking naar boven (int) van de gegeven Parsons code.
Schrijf een functie parsons waaraan de locatie (str) moet doorgegeven worden van een tekstbestand dat de contourplot van een Parsons code bevat. De functie moet de corresponderende Parsons code (str) teruggeven (in hoofdletters).
Schrijf een functie contour waaraan een Parsons code (str) moet doorgegeven worden. De functie moet de contourplot van de gegeven Parsons code uitschrijven. De functie heeft ook nog een tweede optionele parameter waaraan de locatie (str) van een tekstbestand kan doorgegeven worden. Als er expliciet een waarde wordt doorgegeven aan de tweede parameter dan moet de functie de contourplot niet uitschrijven, maar wegschrijven naar dit tekstbestand. Als het tekstbestand nog niet bestond dan moet het nieuw aangemaakt worden. Als het tekstbestand wel al bestond dan moet het overschreven worden.
Strings in Python gebruiken het backslash karakter (\) voor het escapen van karakters die anders een speciale betekenis zouden krijgen, zoals een newline ('\n'), een enkel aanhalingsteken ('\'') of een dubbel aanhalingsteken ("\""). Om letterlijke backslashes op te nemen in strings (ook docstrings) moeten die backslashes dus verdubbeld worden:
>>> print('Antwoord met ja\neen') Antwoord met ja een >>> print('Antwoord met ja\\neen') Antwoord met ja\neen
In onderstaande voorbeeldsessie gaan we ervan uit dat de tekstbestanden parsons_01.txt16, parsons_02.txt17 en parsons_03.txt18 zich in de huidige directory bevinden.
>>> maximale_afwijking('*RUURDDDDRUURDR') (-2, 2) >>> maximale_afwijking('*uduududdduu') (-1, 2) >>> maximale_afwijking('*DRRUUDDRUURDUDURDDU') (-1, 1) >>> parsons('parsons_01.txt19') '*RUURDDDDRUURDR' >>> parsons('parsons_02.txt20') '*UDUUDUDDDUU' >>> parsons('parsons_03.txt21') '*DRRUUDDRUURDUDURDDU' >>> contour('*RUURDDDDRUURDR') *-* / \ * * / \ *-* * *-* \ / \ * * *-* \ / *-* >>> contour('*RUURDDDDRUURDR', 'contour_01.txt22') >>> contour('*uduududdduu') * * / \ / \ * * * * * / \ / \ / * * * * \ / * >>> contour('*uduududdduu', 'contour_02.txt23') >>> contour('*DRRUUDDRUURDUDURDDU') * *-* * *-* / \ / \ / \ / \ * * * * * * * * \ / \ / \ / *-*-* *-* * >>> contour('*DRRUUDDRUURDUDURDDU', 'contour_03.txt24')