De Parsons-code is een eenvoudige notatiemethode om muziek te identificeren aan de hand van melodische bewegingen — bewegingen van de toonhoogte omhoog, omlaag of statisch.

Deze rode lijn is een grafische weergave van de Parsons-code van het traditioneel Engels kerstlied We Wish You A Merry Christmas:
URUDDDRRURUDDDDRURUDDDDDRUUDUDU
Elk paar opeenvolgende noten van een melodie wordt aangeduid met één van drie mogelijke hoofdletters die het verband leggen tussen de toonhoogte van de volgende noot en die van de vorige noot:
U (omhoog; up): de volgende noot is hoger dan de vorige noot
D (omlaag; down): de volgende noot is lager dan de vorige noot
R (herhaald; repeat): de volgende noot is even hoog als de vorige noot
Elke hoofdletter U, D of R in een Parsons-code wordt een beweging genoemd.
Denys Parsons ontwikkelde dit systeem voor zijn boek The Directory of Tunes and Musical Themes uit 1975. Door muziek op deze manier voor te stellen, wordt het makkelijker om melodieën te indexeren, te analyseren of te zoeken. Vooral wanneer de noten onbekend zijn. Parsons behandelde ongeveer 15.000 klassieke, populaire en volksmuziekstukken in zijn boek. Daarbij ontdekte hij dat UU de meest populaire openingsbeweging is. Ze komt voor in 23% van alle melodieën. Een fenomeen dat wordt waargenomen in alle muziekgenres.
Schrijf een bash shell script parsons waarmee een grafische weergave van Parsons-codes kan uitgeschreven worden naar standaard uitvoer (stdout) in SVG-formaat. Verderop bespreken we stap voor stap hoe deze SVG-afbeelding opgebouwd wordt. Het script moet bijvoorbeeld kunnen gebruikt worden om deze weergave van zeven Parsons-codes te genereren in de regenboogkleuren.

De Parsons-codes die we willen weergeven, moeten als afzonderlijke argumenten aan het script doorgegeven worden.
De kleur van een individuele Parsons-code kan vastgelegd worden door de code zelf te laten volgen door een dubbelpunt (:) en een HTML-kleur, bijvoorbeeld URUDDDRRUR:red voor een Parsons-code die als een rode lijn moet weergegeven worden. Als er geen specifieke kleur wordt opgegeven voor een Parsons-code, dan moet het script die weergeven in een standaardkleur die voor alle Parsons-codes zonder specifieke kleur gebruikt wordt.
Het script moet de volgende opties ondersteunen:
optie -c <string>: gebruik de HTML-kleur die aan deze optie wordt doorgegeven als standaardkleur voor alle Parsons-codes zonder specifieke kleur (standaardwaarde: white)
optie -g: toon roosterpunten (grijze punten) in de achtergrond; standaard worden de roosterpunten niet weergegeven
optie -s: beperk de lengte waarmee Parsons-codes worden weergegeven tot die van de kortste Parsons-code die aan het script wordt doorgegeven; standaard wordt elke Parsons-code over zijn volle lengte weergegeven
Het script moet voor de verwerking van de opties de flexibiliteit aan de dag leggen die gebruikelijk is bij Unix commando's: volgorde van opties speelt geen rol, opties kunnen samengenomen worden, argument bij een optie moet niet noodzakelijk van de optieletter gescheiden worden door witruimte, ….
Daarnaast moet het script de volgende foutafhandeling voorzien:
als niet de gepaste opties doorgegeven worden (enkel ondersteuning voor de opties -c, -g en -s, waarbij verplicht een argument aan de optie -c moet doorgegeven worden), dan moet het script een gepaste boodschap uitschrijven naar stderr en eindigen met exit status 1
als er aan het script geen argumenten doorgegeven worden, dan moet het script een gepaste boodschap uitschrijven naar stderr en eindigen met exit status 2
als er aan het script een argument wordt doorgegeven dat geen geldige Parsons-code is (een string die bestaat uit één of meer hoofdletters U, D en R), optioneel gevolgd door een dubbelpunt (:) en een HTML-kleur (een string die bestaat uit één of meer karakters die geen dubbelpunt zijn), dan moet het script een gepaste boodschap uitschrijven naar stderr en eindigen met exit status 3
Hierbij hebben we de foutafhandeling in volgorde van prioriteit opgelijst. De gepaste foutboodschappen vind je terug in onderstaand voorbeeld.
Scalable Vector Graphics (SVG) is een XML-gebaseerd bestandsformaat dat vectorafbeeldingen tekstueel beschrijft aan de hand van eenvoudige meetkundige bouwstenen zoals punten, lijnen, cirkels en veelhoeken.
Je moet geen SVG of XML kennen om deze opgave op te lossen. We bespreken stap voor stap hoe de grafische weergave van Parsons-codes in SVG-formaat opgebouwd wordt aan de hand van vier sjablonen: hoofding, rooster, Parsons-code en voettekst. Daarbij zullen we de variabele onderdelen van elk sjabloon in het groen weergeven. Daar moet het script de juiste waarden invullen. Het is belangrijk dat elk sjabloon exact overgenomen wordt, zodat het resultaat dat het script uitschrijft precies overeenkomt met de beschreven specificatie.
<svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="-0.5 -7.5 32 13">
<style type="text/css">path{fill:none;stroke-width:0.25;stroke-linecap:round;stroke-linejoin:round}</style>
<rect x="-0.5" y="-7.5" width="32" height="13" fill="black" rx="0.2"/>
Dit sjabloon bevat de SVG start-tag (svg) en algemene opmaak van de afbeelding (style). Het tekent ook een afgeronde zwarte rechthoek (rect) als achtergrond. Op de eerste en de derde regel van het sjabloon moeten dezelfde drie natuurlijke getallen ingevuld worden: i) de bovengrens van de uitwijkingen $$\Delta_{+}$$, ii) de breedte $$b + 1$$ en iii) de hoogte $$h + 1$$ van de collectie Parsons-codes die aan het script doorgegeven werden. Merk op dat het minteken (-) dat voorafgaat aan het eerste natuurlijke getal dat moet ingevuld worden, en de .5 die erop volgt, vaste onderdelen vormen van het sjabloon.
De breedte $$b$$ van een collectie Parsons-codes is standaard gelijk aan de lengte van de langste Parsons-code, waarbij de lengte van een Parsons-code uitgedrukt wordt als het aantal bewegingen (letters U, D en R) in de Parsons-code. Als de optie -s gebruikt werd, dan is de breedte echter gelijk aan de lengte van de kortste Parsons-code.
De uitwijking van een Parsons-code geeft de hoogte van de grafische weergave aan bij de start en na elke beweging (een letter U, D of R). De weergave van elke Parsons-code start in de oorsprong $$(0, 0)$$ van een cartesisch coördinatenstelsel (X- en Y-as die loodrecht op elkaar staan) en start dus met uitwijking 0. Bij elke beweging U stijgt de uitwijking met 1. Bij elke beweging D daalt de uitwijking met 1. Bij elke beweging R blijft de uitwijking gelijk. Voor de rode Parsons-code
URUDDDRRURUDDDDRURUDDDDDRUUDUDU
die we eerder als voorbeeld gebruikten, verloopt de uitwijking op deze manier

De bovengrens van de uitwijkingen $$\Delta_{+}$$ van een collectie Parsons-codes is de maximale uitwijking langs alle Parsons-codes. Omdat de uitwijking van een Parsons-code altijd start bij 0, geldt dat $$\Delta_{+} \geq 0$$. Voor de twee Parsons-codes in onderstaande afbeelding wordt de bovengrens $$\Delta_{+} = 7$$ bereikt langs de oranje Parsons-code.
De ondergrens van de uitwijkingen $$\Delta_{-}$$ van een collectie Parsons-codes is de minimale uitwijking langs alle Parsons-codes. Omdat de uitwijking van een Parsons-code altijd start bij 0, geldt dat $$\Delta_{-} \leq 0$$. Voor de twee Parsons-codes in onderstaande afbeelding wordt de ondergrens $$\Delta_{-} = -6$$ bereikt langs de rode Parsons-code.
Als de optie -s gebruikt wordt, dan worden de bovengrens en ondergrens van de uitwijkingen enkel berekend langs de eerste $$b$$ bewegingen van elke Parsons-code. Daarbij is $$b$$ de breedte van de collectie Parsons-codes.

De hoogte $$h$$ van een collectie Parsons-codes is gelijk aan $$\Delta_{+} - \Delta_{-}$$. Voor de twee Parsons-codes in bovenstaande afbeelding is de hoogte $$h = 7 - (-6) = 13$$.
<defs><pattern id="grid" viewBox="0,0,1,1" x="-0.5" y="-0.5" width="1" height="1" patternUnits="userSpaceOnUse">
<circle cx="0.5" cy="0.5" r="0.125" fill="#444"/></pattern></defs>
<polygon points="-0.5,0 31.5,-32 31.5,32" fill="url(#grid)"/>
Dit sjabloon tekent roosterpunten (grijze punten) in de achtergrond en moet enkel aan de SVG-afbeelding toegevoegd worden als de optie -g gebruikt wordt. Op de derde regel van het sjabloon moeten de vier natuurlijke getallen $$b$$, $$b + 1$$, $$b$$ en $$b + 1$$ ingevuld worden, met $$b$$ de breedte van de collectie Parsons-codes die aan het script doorgegeven werden. De mintekens (-) en halve waarden (.5) vormen opnieuw vaste onderdelen van het sjabloon.
<path d="M0,0l1,-1h1l1,-1l1,1l1,1l1,1h1h1l1,-1h1" stroke="red"/>
Voor elk argument dat aan het script werd doorgegeven — een Parsons-code die optioneel een specifieke kleur meekrijgt — moet aan de SVG-afbeelding een afzonderlijke regel toegevoegd worden die opgebouwd is volgens dit sjabloon. Het sjabloon tekent de Parsons-code als een gekleurde lijn (path) die start in de oorsprong $$(0, 0)$$ van een cartesisch coördinatenstelsel.
De waarde die moet ingevuld worden voor het attribuut d krijg je door in de Parsons-code
elke letter U te vervangen door l1,-1
elke letter D te vervangen door l1,1
elke letter R te vervangen door h1
vooraan M0,0 toe te voegen
Voor de duidelijkheid: het fragment l1,-1 dat in de plaats komt van elke U in de Parsons-code is een kleine letter l, gevolgd door het cijfer 1, een komma, een minteken (-) en nog een cijfer 1. Het fragment dat in de plaats komt van elke D is hetzelfde, maar dan zonder minteken (-). Als de optie -s gebruikt werd, dan worden enkel de eerste $$b$$ bewegingen van de Parsons-code gebruikt, met $$b$$ de breedte van de collectie Parsons-codes die aan het script doorgegeven werden.
De waarde die in het sjabloon moet ingevuld worden voor het attribuut stroke is de specifieke kleur die in het argument werd opgegeven voor de Parsons-code, of de standaardkleur als er geen specifieke kleur werd opgegeven.
De waarden die in het sjabloon als voorbeeld ingevuld werden, corresponderen met die voor een argument URUDDDRRUR:red of met die voor een argument URUDDDRRUR en de kleur red die als standaardkleur werd doorgegeven aan de optie -c.
</svg>
Dit laatste sjabloon sluit de SVG-afbeelding af met een SVG stop-tag.
Onderstaande voorbeeldsessie toont hoe het shell script parsons moet kunnen gebruikt worden.
$ parsons URUDDDRRUR:red > merry_xmas.svg
$ cat merry_xmas.svg
<svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="-0.5 -2.5 11 4">
<style type="text/css">path{fill:none;stroke-width:0.25;stroke-linecap:round;stroke-linejoin:round}</style>
<rect x="-0.5" y="-2.5" width="11" height="4" fill="black" rx="0.2"/>
<path d="M0,0l1,-1h1l1,-1l1,1l1,1l1,1h1h1l1,-1h1" stroke="red"/>
</svg>
$ parsons -gc red URUDDDRRUR > merry_xmas.grid.svg
$ cat merry_xmas.grid.svg
<svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="-0.5 -2.5 11 4">
<style type="text/css">path{fill:none;stroke-width:0.25;stroke-linecap:round;stroke-linejoin:round}</style>
<rect x="-0.5" y="-2.5" width="11" height="4" fill="black" rx="0.2"/>
<defs><pattern id="grid" viewBox="0,0,1,1" x="-0.5" y="-0.5" width="1" height="1" patternUnits="userSpaceOnUse">
<circle cx="0.5" cy="0.5" r="0.125" fill="#444"/></pattern></defs>
<polygon points="-0.5,0 10.5,-11 10.5,11" fill="url(#grid)"/>
<path d="M0,0l1,-1h1l1,-1l1,1l1,1l1,1h1h1l1,-1h1" stroke="red"/>
</svg>
$ parsons -g URUDDDRRURUDDDDRURUDDDDDRUUDUDU:red UDDUUUUUUUUDDDDDUURRUDDRRUDDUDD:orange UDDDRRRUDDDRUDDDURDDUDUDDDRUDDD:yellow UURRDUURDRUUDRDDDUDUURRDUURDRUU:lime UDDUUDDURDURDURUDDDUDDURUDDDUDD:lightblue RUDUDRUDRDRRUUDDRDUDRDRDUDUDRUR:blue URRUUDUUUDUDDURDDURRUUDUUUDUDDU:blueviolet > xmas_rainbow.svg
$ cat xmas_rainbow.svg
<svg xmlns="http://www.w3.org/2000/svg" width="100%" viewBox="-0.5 -7.5 32 19">
<style type="text/css">path{fill:none;stroke-width:0.25;stroke-linecap:round;stroke-linejoin:round}</style>
<rect x="-0.5" y="-7.5" width="32" height="19" fill="black" rx="0.2"/>
<defs><pattern id="grid" viewBox="0,0,1,1" x="-0.5" y="-0.5" width="1" height="1" patternUnits="userSpaceOnUse">
<circle cx="0.5" cy="0.5" r="0.125" fill="#444"/></pattern></defs>
<polygon points="-0.5,0 31.5,-32 31.5,32" fill="url(#grid)"/>
<path d="M0,0l1,-1h1l1,-1l1,1l1,1l1,1h1h1l1,-1h1l1,-1l1,1l1,1l1,1l1,1h1l1,-1h1l1,-1l1,1l1,1l1,1l1,1l1,1h1l1,-1l1,-1l1,1l1,-1l1,1l1,-1" stroke="red"/>
<path d="M0,0l1,-1l1,1l1,1l1,-1l1,-1l1,-1l1,-1l1,-1l1,-1l1,-1l1,-1l1,1l1,1l1,1l1,1l1,1l1,-1l1,-1h1h1l1,-1l1,1l1,1h1h1l1,-1l1,1l1,1l1,-1l1,1l1,1" stroke="orange"/>
<path d="M0,0l1,-1l1,1l1,1l1,1h1h1h1l1,-1l1,1l1,1l1,1h1l1,-1l1,1l1,1l1,1l1,-1h1l1,1l1,1l1,-1l1,1l1,-1l1,1l1,1l1,1h1l1,-1l1,1l1,1l1,1" stroke="yellow"/>
<path d="M0,0l1,-1l1,-1h1h1l1,1l1,-1l1,-1h1l1,1h1l1,-1l1,-1l1,1h1l1,1l1,1l1,1l1,-1l1,1l1,-1l1,-1h1h1l1,1l1,-1l1,-1h1l1,1h1l1,-1l1,-1" stroke="lime"/>
<path d="M0,0l1,-1l1,1l1,1l1,-1l1,-1l1,1l1,1l1,-1h1l1,1l1,-1h1l1,1l1,-1h1l1,-1l1,1l1,1l1,1l1,-1l1,1l1,1l1,-1h1l1,-1l1,1l1,1l1,1l1,-1l1,1l1,1" stroke="lightblue"/>
<path d="M0,0h1l1,-1l1,1l1,-1l1,1h1l1,-1l1,1h1l1,1h1h1l1,-1l1,-1l1,1l1,1h1l1,1l1,-1l1,1h1l1,1h1l1,1l1,-1l1,1l1,-1l1,1h1l1,-1h1" stroke="blue"/>
<path d="M0,0l1,-1h1h1l1,-1l1,-1l1,1l1,-1l1,-1l1,-1l1,1l1,-1l1,1l1,1l1,-1h1l1,1l1,1l1,-1h1h1l1,-1l1,-1l1,1l1,-1l1,-1l1,-1l1,1l1,-1l1,1l1,1l1,-1" stroke="blueviolet"/>
</svg>
$ parsons -x URUDDDRRUR
Syntax: parsons [-gs] [-c <color>] code[:color] ...
$ echo $?
1
$ parsons
Syntax: parsons [-gs] [-c <color>] code[:color] ...
$ echo $?
2
$ parsons ABC
Syntax: parsons [-gs] [-c <color>] code[:color] ...
$ echo $?
3
$ parsons URUDDDRRUR:blue:yellow
Syntax: parsons [-gs] [-c <color>] code[:color] ...
$ echo $?
3
In deze opgave gebruiken we zeven Parsons-codes als voorbeeld. Ze stellen allemaal bekende kerstliedjes voor. Hieronder staan ze opgelijst in volgorde van de regenboogkleuren die we eraan toegekend hebben:
| kleur | HTML-kleur | kerstliedje | Parsons-code |
|---|---|---|---|
| rood | red | We Wish You A Merry Christmas | URUDDDRRURUDDDDRURUDDDDDRUUDUDU |
| oranje | orange | White Christmas | UDDUUUUUUUUDDDDDUURRUDDRRUDDUDD |
| geel | yellow | Jingle Bells | UDDDRRRUDDDRUDDDURDDUDUDDDRUDDD |
| groen | lime | Once In Royal David's City | UURRDUURDRUUDRDDDUDUURRDUURDRUU |
| blauw | lightblue | Silent Night | UDDUUDDURDURDURUDDDUDDURUDDDUDD |
| indigo | blue | Fairytale Of New York | RUDUDRUDRDRRUUDDRDUDRDRDUDUDRUR |
| violet | blueviolet | O Little Town Of Bethlehem | URRUUDUUUDUDDURDDURRUUDUUUDUDDU |
Met de Melodic Contour Search tool van Musipedia kan je Parsons-codes gebruiken om liedjes te zoeken.