diff --git a/web/cgi-bin/horas/dialogcommon.pl b/web/cgi-bin/horas/dialogcommon.pl index f3b54d4cd5e..9aa3781ef20 100644 --- a/web/cgi-bin/horas/dialogcommon.pl +++ b/web/cgi-bin/horas/dialogcommon.pl @@ -128,6 +128,9 @@ sub get_dayname_for_condition { missa => sub {$missanumber}, communi => sub { {summpont => ($version =~ /1960/ || $version =~ /1955/ || $version =~ /Divino/)} }, 'die' => \&get_dayname_for_condition, + tonus => sub {$chantTone}, + tonus => sub {$chantTone}, + hora => sub {$hora}, ); our %predicates = ( tridentina => sub { shift =~ /Trident/ }, @@ -142,6 +145,7 @@ sub get_dayname_for_condition { longior => sub { shift == 1 }, brevior => sub { shift == 2 }, 'summorum pontificum' => sub { ${shift()}{summpont} }, + 'in solemnitatibus' => sub { shift =~ /solemnis|resurrectionis/i }, ); # parse and evaluate a condition diff --git a/web/cgi-bin/horas/horas.pl b/web/cgi-bin/horas/horas.pl index bf2b3567dca..9e1d32d7b43 100644 --- a/web/cgi-bin/horas/horas.pl +++ b/web/cgi-bin/horas/horas.pl @@ -37,11 +37,23 @@ sub horas { our $recitelimit = 0; $tlang = ($lang1 !~ /Latin/) ? $lang1 : $lang2; our %translate; - $translate{$lang1} = setupstring($lang1, "Psalterium/Translate.txt"); - $translate{$lang2} = setupstring($lang2, "Psalterium/Translate.txt"); - cache_prayers(); %chant = %{setupstring('Latin', "Psalterium/Chant.txt")}; $column = 1; + + # Ensure no chant is displayed at the little hours during the Triduum + my $templang1 = $lang1; # save settings for later + my $templang2 = $lang2; + my $temponly = $only; + if (triduum_gloria_omitted() && $hora =~ /Prima|Tertia|Sexta|Nona|Completorium/i) { + $lang1 =~ s/\-gabc//; + $lang2 =~ s/\-gabc//; + $only = ($lang1 eq $lang2); + precedence(); setsecondcol(); #fills our hashes et variables + } + + $translate{$lang1} = setupstring($lang1, "Psalterium/Translate.txt"); + $translate{$lang2} = setupstring($lang2, "Psalterium/Translate.txt"); + cache_prayers(); if ($Ck) { $version = $version1; precedence(); } @script1 = getordinarium($lang1, $command); @script1 = specials(\@script1, $lang1); @@ -80,7 +92,7 @@ sub horas { $text1 =~ s/$alleluia_regex//g; } $text1 =~ s/\\s*\/\/g; - if ($lang1 =~ /Latin/i) { $text1 = spell_var($text1); } + if ($lang1 =~ /Latin$/i) { $text1 = spell_var($text1); } # Spell check not for 'Latin-gabc' (destroys chant) if ($text1 && $text1 !~ /^\s+$/) { setcell($text1, $lang1); } if (!$only) { @@ -92,7 +104,7 @@ sub horas { $text2 =~ s/$alleluia_regex//ig; } $text2 =~ s/\\s*\/\/g; - if ($lang2 =~ /Latin/i) { $text2 = spell_var($text2); } + if ($lang2 =~ /Latin$/i) { $text2 = spell_var($text2); } # Spell check not for 'Latin-gabc' (destroys chant) if ($text2 && $text2 !~ /^\s+$/) { setcell($text2, $lang2); } } } @@ -104,6 +116,11 @@ sub horas { } table_end(); if ($column == 1) { $searchind++; } + + # restore original values if changed + $lang1 = $templang1; + $lang2 = $templang2; + $only = $temponly; } #*** getunits(\@s, $ind) @@ -280,12 +297,47 @@ sub teDeum : ScriptFunc { return "\n_\n!Te Deum\n$prayers{$lang}->{'Te Deum'}"; } +#*** Deus_in_adjutorium($lang) +# return Ferial, Festal, or Solemn chant +sub Deus_in_adjutorium : ScriptFunc { + my $lang = shift; + our %prayers; + + our ($winner, @dayname); + my %latwinner = %{setupstring('Latin', $winner)}; + my @latrank = split(';;', $latwinner{Rank}); + my $latname = $latrank[0]; + my $latrank = $latrank[2]; + + # Ferial chant for all Little hours and Ferials and Simples + if ($lang !~ /gabc/ || $hora !~ /matutinum|laudes|vespera/i || $rank < 2 || $latname =~ /Feria|Sabbato|Vigilia(?! Epi)/i || $latrank < 2) { + our $incipitTone = 'ferial'; + return $prayers{$lang}->{'Deus in adjutorium'}; + } + + our $chantTone; # has been filled by setChantTone() @horascommon.pl + if ($hora !~ /vespera/i || $chantTone !~ /solemnis|resurrectionis/i) { + our $incipitTone = 'festal'; + return $prayers{$lang}->{'Deus in adjutorium1'}; # Festal tone + } else { # Solemn Vespers only + our $incipitTone = 'solemn'; + return $prayers{$lang}->{'Deus in adjutorium2'}; # Solemn tone + } +} + #*** Alleluia($lang) # return the text Alleluia or Laus tibi sub Alleluia : ScriptFunc { my $lang = shift; - our %prayers; + our (%prayers, $incipitTone); my $text = $prayers{$lang}->{'Alleluia'}; + + if ($lang =~ /gabc/i && $incipitTone) { + $text = ($incipitTone =~ /festal/i) ? $prayers{$lang}->{'Alleluia1'} + : ($incipitTone =~ /solemn/i) ? $prayers{$lang}->{'Alleluia2'} + : $text; + } + my @text = split("\n", $text); if ($dayname[0] =~ /Quad/i && !Septuagesima_vesp()) { @@ -391,12 +443,18 @@ sub Dominus_vobiscum2 : ScriptFunc { #* officium defunctorum # adds Alleluia, alleluia for Pasc0 sub Benedicamus_Domino : ScriptFunc { my $lang = shift; - our %prayers; - my $text = $prayers{$lang}->{'Benedicamus Domino'}; - if (Septuagesima_vesp()) { $text = $prayers{$lang}->{'Benedicamus Domino1'}; } - if ($dayname[0] !~ /Pasc0/i || $hora !~ /(Laudes|Vespera)/i) { return $text; } - my @text = split("\n", $text); - return "$text[0] $prayers{$lang}->{'Alleluia Duplex'}\n$text[1] $prayers{$lang}->{'Alleluia Duplex'}\n"; + our (%prayers, @dayname, $hora, $vespera); + + our $chantTone; # filled by setChantTone() @horascommon.pl + + if (Septuagesima_vesp() || ($dayname[0] =~ /Pasc0/i && $hora =~ /(Laudes|Vespera)/i) && ($lang !~ /gabc/i || $chantTone !~ /resurrectionis/i)) { + return $prayers{$lang}->{'Benedicamus Domino1'}; # Paschal octave (Feria IV - Sabbato) + } elsif ($lang !~ /gabc/i || $hora !~ /(Matutinum|Laudes|Vespera)/i) { + return $prayers{$lang}->{'Benedicamus Domino'}; # Little hours + } + + my %benedicamus = %{setupstring($lang, 'Psalterium/Benedicamus.txt')}; + return ($benedicamus{"$chantTone$vespera"}) || ($benedicamus{"$chantTone"}) || ($prayers{'Latin'}->{'Benedicamus Domino'}); } #*** antiphona_finalis @@ -436,7 +494,7 @@ sub psalm : ScriptFunc { my @a = @_; my ($num, $lang, $antline, $nogloria); - + if (@a < 4) { $num = shift @a; if ($a[0] =~ /^1$/) { @@ -449,7 +507,7 @@ sub psalm : ScriptFunc { $lang = $a[3]; $antline = $a[4]; } - + my $canticlef = 230 < $num && $num < 234; if ($num =~ /^-(.*)/) { @@ -483,15 +541,33 @@ sub psalm : ScriptFunc { # the invitatory, lives elsewhere, and is loaded here only for its # special third-nocturn use on the day of the Epiphany. my $fname = ($psnum == 94) ? 'Psalterium/Invitatorium1.txt' : "$psalmfolder/Psalm$psnum.txt"; + my $ftone = ''; # to save the chant tone to retrieve the Gloria Patri below if ($version =~ /1960|Newcal/) { $fname =~ s/Psalm226/Psalm226r/; } if ($version =~ /1960|Newcal/ && $num !~ /\(/ && $dayname[0] =~ /Nat/i) { $fname =~ s/Psalm88/Psalm88r/; } if ($version =~ /1960|Newcal/ && $num !~ /\(/ && $month == 8 && $day == 6) { $fname =~ s/Psalm88/Psalm88a/; } - $fname = checkfile($lang, $fname); + + # select right Psalm file + if ($lang =~ /gabc/i) { + if($num > 230 && $num < 233) { $num .= ",$canticaTone"; } + $fname = ($num =~ /,/) ? "$psalmfolder/$num.gabc" : "$psalmfolder/Psalm$num.txt"; # distingiush between chant and text + $fname =~ s/\:/\./g; + $fname =~ s/,/-/g; # file name with dash not comma + $num =~ s/\:\:/ \& /g; # Multiple Psalms joined together + $num =~ s/\:/; Part: /; # n-th Part of Psalm + $num =~ s/,,.*?,,//; + $num =~ s/,/; Tone: /; # name Tone in Psalm headline + $ftone = ($num =~ /Tone: (.*)/) ? $1 : ''; + if (!(-e "$datafolder/$lang/$fname")) { + $num =~ s/;.*//; + $fname = "$psalmfolder/Psalm$num.txt"; + } + } + $fname = checkfile($lang, $fname); # load psalm my(@lines) = do_read($fname); unless (@lines > 0) { - return "$t$datafolder/$lang/$psalmfolder/Psalm$psnum.txt not found"; + return "$fname not found"; } # Extract limits of the division of the psalm. (potentially within a psalm verse) @@ -507,7 +583,7 @@ sub psalm : ScriptFunc { my $title = translate('Psalmus', $lang) . " $num"; my $source; - if ($num > 150 && $num < 300 && @lines) { + if ($num > 150 && $num < 300 && @lines && $fname !~ /\.gabc/) { shift(@lines) =~ /\(?(?.*?) \* (?<source>.*?)\)?\s*$/; ($title, $source) = ($+{title}, $+{source}); if ($v1) { $source =~ s/:\K.*/"$v1-$v2"/e; } @@ -522,9 +598,15 @@ sub psalm : ScriptFunc { my $formatted_antline; my $first = $antline; my $initial = $nonumbers; - + my $gabc = 0; + foreach my $line (@lines) { + if ($lang =~ /gabc/i && !$gabc && $line =~ /^(name:|\([cf][1-4]\))/) { + $gabc = 1; + $line = "{" . $line; # append brace, s.t. gabc is recognized by webdia.pl + } + # Interleave antiphon into the psalm "Venite exsultemus". if ($psnum == 94 && $line =~ /^\s*\$ant\s*$/) { $formatted_antline ||= setfont($redfont, 'Ant.') . " $antline"; @@ -532,6 +614,14 @@ sub psalm : ScriptFunc { next; } + if ($gabc) { + if ($line !~ /\S/) { last; } + $line =~ s/(\s)_([\^\s*]+)_(\(\))?(\s)/$1\^_$2_\^$3$4/g; # ensure red digits for chant + $line =~ s/(\([cf][1-4]\)|\s?)(\d+\.)(\s\S)/$1\^$2\^$3/g; + $t .= " \n$line"; + next; + } + if ($line =~ /^\s*([0-9]+)\:([0-9]+)([abc]?)/) { $v = $2; $cc = $3; } elsif ($line =~ /^\s*([0-9]+)([abc]?)/) { @@ -584,9 +674,22 @@ sub psalm : ScriptFunc { $rest =~ s/^\s*([a-z])/uc($1)/ei; $t .= "\n$lnum $line $rest"; } - $t .= "\n"; + $t .= $gabc ? "}\n" : "\n"; # end chant with brace for recognition if ($version =~ /Monastic/ && $num == 129 && $hora eq 'Prima') { $t .= $prayers{$lang}->{Requiem}; } - elsif ($num != 210 && !$nogloria) { $t .= "\&Gloria\n"; } + elsif ($num != 210 && !$nogloria ) { + if ($gabc && !triduum_gloria_omitted()) { + $fname = "$psalmfolder/gloria-$ftone.gabc"; + $fname =~ s/,/-/g; # file name with dash not comma + $fname = checkfile($lang, $fname); + my(@lines) = do_read($fname); + foreach my $line (@lines) { + $t =~ s/\}\n$/ \n$line\}\n/; + } + # $t .= "$fname\n"; + } else { + $t .= "\&Gloria\n"; + } + } $t .= settone(0); return $t; } @@ -886,20 +989,23 @@ sub translate { #*** ant_Benedictus($num, $lang) # returns the antiphona $num=1 = for beginning =2 for end sub ant_Benedictus : ScriptFunc { - my $num = shift; my $lang = shift; our ($version, $winner); our ($month, $day); our $duplex; - + my ($ant) = getantvers('Ant', 2, $lang); - + if ($month == 12 && ($day == 21 || $day == 23) && $winner =~ /tempora/i) { my %specials = %{setupstring($lang, "Psalterium/Major Special.txt")}; $ant = $specials{"Adv Ant $day" . "L"}; } - my @ant_parts = split('\*', $ant); + + my @ant_parts = split('\*', $ant); + if ($lang =~ /gabc/i && $ant =~ /\{.*\}/) { + $ant_parts[0] =~ s/(.*)(\(.*?\))\s*$/$1\.$2 (::)\}/; # Un-duplicate GABC Antiphon + } if ($num == 1 && $duplex < 3 && $version !~ /196/) { return "Ant. $ant_parts[0]"; } if ($num == 1) { @@ -913,34 +1019,38 @@ sub ant_Benedictus : ScriptFunc { #*** ant_Magnificat($num, $lang) # returns the antiphon for $num=1 the beginning, or =2 for the end sub ant_Magnificat : ScriptFunc { - - my $num = shift; #1=before, 2=after - my $lang = shift; - - our ($version, $winner); - our ($month, $day); - our $duplex; - our $rank; - our $vespera; - - my $v = ($version =~ 1960 && $winner =~ /Sancti/i && $rank < 5) ? 3 : $vespera; - my ($ant) = getantvers('Ant', $v, $lang); - - # Special processing for Common of Supreme Pontiffs. Confessor-Popes - # have a common Magnificat antiphon at second Vespers. + + my $num = shift; #1=before, 2=after + my $lang = shift; + + our ($version, $winner); + our ($month, $day); + our $duplex; + our $rank; + our $vespera; + + my $v = ($version =~ 1960 && $winner =~ /Sancti/i && $rank < 5) ? 3 : $vespera; + my ($ant) = getantvers('Ant', $v, $lang); + + # Special processing for Common of Supreme Pontiffs. Confessor-Popes + # have a common Magnificat antiphon at second Vespers. my $popeclass = ''; if ($version !~ /Trident/i && $v == 3 && ( (undef, $popeclass, undef) = papal_rule($winner{Rule})) && $popeclass =~ /C/i) { - $ant = papal_antiphon_dum_esset($lang); + $ant = papal_antiphon_dum_esset($lang); setbuild2("subst: Special Magnificat Ant. Dum esset"); - } + } - if ($month == 12 && ($day > 16 && $day < 24) && $winner =~ /tempora/i) { - my %specials = %{setupstring($lang, "Psalterium/Major Special.txt")}; - $ant = $specials{"Adv Ant $day"}; - $num = 2; - } - my @ant_parts = split('\*', $ant); + if ($month == 12 && ($day > 16 && $day < 24) && $winner =~ /tempora/i) { + my %specials = %{setupstring($lang, "Psalterium/Major Special.txt")}; + $ant = $specials{"Adv Ant $day"}; + $num = 2; + } + + my @ant_parts = split('\*', $ant); + if ($lang =~ /gabc/i && $ant =~ /\{.*\}/) { + $ant_parts[0] =~ s/(.*)(\(.*?\))\s*$/$1\.$2 (::)\}/; # Un-duplicate GABC Antiphon + } if ($num == 1 && $duplex < 3 && $version !~ /196/) { return "Ant. $ant_parts[0]"; } if ($num == 1) { @@ -1334,6 +1444,12 @@ (\$$) # Don't do anything to null antiphons. return unless $$ant; + + if ($lang =~ /gabc/i && $$ant =~ /;;(.*)/) { # strip tone from Antiphone and save it + our $canticaTone = $1; + $$ant =~ s/;;.*//; + } + process_inline_alleluias($$ant); ensure_single_alleluia($$ant, $lang) if alleluia_required($dayname[0], $votive); } diff --git a/web/cgi-bin/horas/horascommon.pl b/web/cgi-bin/horas/horascommon.pl index 0e5ce7a73b2..c6252327dbb 100644 --- a/web/cgi-bin/horas/horascommon.pl +++ b/web/cgi-bin/horas/horascommon.pl @@ -1486,12 +1486,121 @@ sub setheadline { $rankname = $ranktable[$rank]; } } + if ($lang1 =~ /gabc/i || $lang2 =~ /gabc/i) { # setChantTone if necessary + our $chantTone; + setChantTone(); + if ($lang1 =~ /gabc/i) { + return "$name ~ $rankname : Tonus $chantTone"; # Display Chant Tone in Headline + } + } return "$name ~ $rankname"; + } else { return $dayname[1]; } } +# captures the appropriate chant types for GABC Common Tones +# the function is modeled from setheadline(), hence its clumsy look and feel +sub setChantTone { + + my %latwinner = %{setupstring('Latin', $winner)}; + my @latrank = split(';;', $latwinner{Rank}); + my $name = $latrank[0]; + my $rank = $latrank[2]; + + # read only globals + our(%winner, $winner, @dayname, $version, $day, $month, $year, $dayofweek, $hora, $rule, $commune); + + our $chantTone = 'ferialis'; + + if (($name !~ /(?:Die|Feria|Sabbato|^In Octava)/i) && ($dayname[0] !~ /Pasc[07]/i || $dayofweek == 0 || $name !~ /Pasc|Pent/i)) { + # on all feasts except during the Octaves of Easter and Pentecost + my @tradtable = ('ferialis', 'simplicis', 'festivus minor', 'festivus', + 'festivus major', 'minus solemnis', 'solemnis', 'solemnis'); + my @newtable = ('none', 'ferialis', 'festivus minor', 'festivus minor', 'festivus minor', + 'festivus', 'solemnis', 'solemnis'); + + $chantTone = ($version !~ /196/) ? $tradtable[$rank] : $newtable[$rank]; + + if ($version =~ /19(?:55|60)/ && $winner !~ /Pasc5-3/i && $dayname[1] =~ /feria/i) { $chantTone = 'ferialis'; } + + if ($version =~ /1570/i) { $chantTone =~ s/ major//; } # no Duplex majus yet in 1570 + + if($name =~ /Vigilia Epi/i) { + $chantTone = 'festivus minor'; + } elsif ($name =~ /Vigilia|Quattuor/i) { + $chantTone = 'ferialis major'; + } elsif($name =~ /Sanctæ Fami/i && $version !~ /196/) { + $chantTone = 'festivus major'; + } + + if ($name =~ /Dominica/i) { + #if ($version !~ /trident/i) { + local $_ = getweek($day, $month, $year, $dayofweek == 6 && $hora =~ /Vespera|Completorium/i); + $chantTone = (/Pasc0/i) ? 'resurrectionis' + : (/Pasc7|Pent01/i) ? 'solemnis' + : (/Pasc[1-6]/i) ? 'paschalis' + : (/(Adv[1-4]|Quad[1-6])/i) ? 'dominicalis major' + : (/Nat/i) ? 'festivus minor' + : (/Epi1|Pent02/i && $version !~ /19(?:55|6)/ ) ? 'festivus 8vam priv' + #: (/(Adv[2-4]|Quadp)/i) ? 'Semiduplex Dominica II. classis' + #: (/(Epi[1-6])|Pent[22-23]/i && $dayofweek > 0 && !($dayofweek == 6 && $hora =~ /Vespera|Completorium/i)) ? 'Semiduplex Dominica anticipata' + : 'dominicalis minor'; + #} else { + # local $_ = getweek($day, $month, $year, $dayofweek == 6 && $hora =~ /Vespera|Completorium/i); + # $chantTone = (/Pasc[017]/i || /Pent01/i) ? 'Duplex I. classis' + # : (/(Adv1|Quad1|Quad[5-6])/i) ? 'Semiduplex Dominica I. classis' + # : (/(Adv[2-4]|Quadp|Quad[2-4])/i) ? 'Semiduplex Dominica II. classis' + # : (/(Epi[1-6])|Pent[22-23]/i && $dayofweek > 0 && !($dayofweek == 6 && $hora =~ /Vespera|Completorium/i)) ? 'Simplex Dominica anticipiata' + # : 'Semiduplex Dominica minor'; + #} + } + #} elsif ($version =~ /196/ && $dayname[0] =~ /Pasc[07]/i && $dayofweek > 0 && $winner !~ /Pasc7-0/) { + # $chantTone = 'Dies Octavæ I. classis'; # Paschal & Pentecost Octave post 1960 + } elsif ($version =~ /196/ && $winner =~ /Pasc6-6/) { + $chantTone = 'paschalis'; # Vigilia Pentecostes + #} elsif ($version =~ /196/ && $winner =~ /Pasc5-3/) { + # $chantTone = 'II. classis'; # Vigilia Asc + #} elsif ($version =~ /196/ && $month == 12 && $day > 16 && $day < 25 && $dayofweek > 0) { + # $chantTone = 'II. classis'; # Week before Christmas + } elsif ($rule =~ /C10/) { + $chantTone = 'BMV sabbato'; # BMV Sabbato + } elsif ($version !~ /196/ && $dayname[0] =~ /Pasc0/i && $dayofweek > 0) { + $chantTone = ($rank =~ 7) ? 'resurrectionis' : 'paschalis'; # Paschal Octave + } elsif ($version !~ /196/ && $dayname[0] =~ /Pasc7/i && $dayofweek > 0) { + $chantTone = ($rank =~ 7) ? 'solemnis' : 'paschalis'; # pentecost Octave + } elsif ($version =~ /trid/i && $name =~ /^In Octava(?! Asc)/i) { + $chantTone = 'festivus'; # all other Octaves pre Divino + } elsif ($version =~ /trid/i && $name =~ /in.* Octavam? Asc|post Octavam Asc|Vigilia Pent/i) { + $chantTone = 'paschalis'; # all other Octaves pre Divino + } elsif ($version =~ /trid/i && $name =~ /infra Octavam/i) { + $chantTone = 'festivus minor'; # all other Octaves pre Divino + } elsif ($version =~ /Divino/ && $name =~ /^In Octava|infra Octavam|post Octavam Asc|Vigilia Pent/i) { + $chantTone = ($rank < 2) ? 'festivus minor' # etiam in octava simplici + : ($rank < 3 && $name !~ /Asc|Nat|Cord/i || $name =~ /post|Joan/) ? 'festivus minor' + : ($rank < 3 && $name !~ /Asc/i) ? 'festivus 8vam priv' + : ($rank < 3) ? 'paschalis' + : ($rank < 5 && $name !~ /Asc|Nat|Cord/i) ? 'festivus major' + : ($rank < 5) ? 'festivus major' + : ($rank < 5.61) ? ($name =~ /Asc/i) ? 'paschalis' : 'festivus major' + : ($rank < 6.5) ? 'festivus major' + : 'paschalis' ; + } else { # Default for Ferias + if ($version !~ /196/) { + $chantTone = ($rank < 2) ? 'ferialis' : ($rank < 3) ? 'ferialis major' : ($rank < 5) ? 'ferialis major' : 'ferialis major'; + } else { + $chantTone = ($dayname[0] =~ /Adv|Quad(?!p)/i || $rank > 3) ? 'ferialis major' : 'ferialis'; #$ranktable[$rank]; + } + } + if (($commune =~ /C11/i || $name =~ /(?:Beat|Sanct)(?:ae|æ) Mari/ && $name !~ /Vigil|Sabbato/i) && $chantTone !~ /solemnis/i ) { $chantTone = 'festivus BMV'; } + elsif ($winner =~ /tempora/i && $dayname[0] =~ /Pasc/i && $chantTone =~ /|ferialis/i ) { $chantTone = 'paschalis'; } + # if Feria / Octava T.P. => paschalis + # + return "$chantTone"; +} + + sub subdirname { my($subdir, $version) = @_; $subdir .= 'M' if $version =~ /monastic/i; diff --git a/web/cgi-bin/horas/specials.pl b/web/cgi-bin/horas/specials.pl index b2f581ec53d..fbe64ebd178 100644 --- a/web/cgi-bin/horas/specials.pl +++ b/web/cgi-bin/horas/specials.pl @@ -130,6 +130,9 @@ sub specials { $skipflag = !preces($item); setcomment($label, 'Preces', $skipflag, $lang); setbuild1($item, $skipflag ? 'omit' : 'include'); + if(!$skipflag && $precesferiales && $item =~ /Dominicales/i) { + push(@s, '/:flexis genibus:/'); # as a reminder //TODO: needs to be "translated" + } if (!$skipflag && $hora =~ /Laudes|Tertia|Sexta|Nona|Vespera/) { push(@s, $prayers{$lang}{"Preces feriales $hora"}); } @@ -199,6 +202,7 @@ sub specials { if ($item =~ /Capitulum/i && $hora =~ /Completorium/i) { $tind--; + if ($lang =~ /gabc/i) { push(@s, $t[$tind++]); next; } # GABC: don't look for start of response while ($tind < @t && $t[$tind] !~ /^\s*(?:V|R.br)\./) { push(@s, $t[$tind++]); } my @resp = (); while ($tind < @t && $t[$tind] !~ /^\s*\#/) { push(@resp, $t[$tind++]); } @@ -566,8 +570,8 @@ sub translate_label { # returns 1 = yes or 0 = omit after deciding about the preces sub preces { - return 0 if ( - $winner =~ /C12/i + return 0 if ( + $winner =~ /C12/i || $rule =~ /Omit.*? Preces/i || ($duplex > 2 && $seasonalflag) || $dayname[0] =~ /Pasc[67]/i @@ -602,8 +606,7 @@ sub preces { } } - if ($item =~ /Feriales/i - && $dayofweek && !($dayofweek == 6 && $hora =~ /vespera/i) + if ($dayofweek && !($dayofweek == 6 && $hora =~ /vespera/i) # Domincales at Completorium are also said if Feriales at Vespers! && ($winner !~ /sancti/i && ($rule =~ /Preces/i || $dayname[0] =~ /Adv|Quad(?!p)/i || emberday()) # || ($version !~ /1955|1960|Newcal/ && $winner{Rank} =~ /vigil/i && $dayname[1] !~ /Epi|Pasc/i)) # certain vigils before 1955 && ($version !~ /1955|1960|Newcal/ || $dayofweek =~ /[35]/ || emberday()) # in 1955 and 1960, only Wednesdays, Fridays and emberdays @@ -640,7 +643,8 @@ sub psalmi_minor { my $lang = shift; my %psalmi = %{setupstring($lang, 'Psalterium/Psalmi minor.txt')}; my (@psalmi, $ant, $psalms); - + my $psalmTone; + if ($version =~ /monastic/i) { @psalmi = split("\n", $psalmi{Monastic}); my $i = @@ -658,6 +662,7 @@ sub psalmi_minor { my @a = split(';;', $psalmi[$i]); $ant = chompd($a[1]); $psalms = chompd($a[2]); + if($lang =~ /gabc/i) { $psalmTone = chompd($a[3]); } # retrieve Psalm Tone } elsif ($version =~ /trident/i) { my $daytype = ($dayofweek == 0) ? 'Dominica' : 'Feria'; my %psalmlines = split(/\n|=/, $psalmi{Tridentinum}); @@ -686,9 +691,10 @@ sub psalmi_minor { # Sext and None is different on Sundays. $psalmkey = ($hora =~ /Completorium/i) ? 'Completorium' : "$hora $daytype"; } - ($ant, $psalms) = split(';;', $psalmlines{$psalmkey}); - $ant = chompd($ant); - $psalms = chompd($psalms); + my @a = split(';;', $psalmlines{$psalmkey}); + $ant = chompd($a[0]); + $psalms = chompd($a[1]); + if($lang =~ /gabc/i) { $psalmTone = chompd($a[2]); } # retrieve Psalm Tone } else { @psalmi = split("\n", $psalmi{$hora}); my $i = 2 * $dayofweek; @@ -800,12 +806,22 @@ sub psalmi_minor { if ($w{Rule} =~ /Minores sine Antiphona/i) { $ant = ''; + $psalmTone = ($version =~ /monastic/) ? 'in-dir-monasticus' : 'in-directum'; setbuild2('Sine antiphonae'); } + + if ($lang =~ /gabc/i) { # retrieve Psalm Tone + if ($ant =~ s/;;(.*);;(.*)/;;$1/ ) { # strip from antiphone + $psalmTone = $2; + $ant =~ s/;;\s*$//; + } + } + if ($ant =~ /(.*?)\;\;/s) { $ant = $1; } if ($dayname[0] =~ /Quad/i) { $ant =~ s/[(]*allel[uú][ij]a[\.\,]*[)]*//ig; } if ($ant) { $ant = "Ant. $ant"; } my @ant = split('\*', $ant); + if ($lang =~ /gabc/i && $ant =~ /\{.*\}/) { $ant[0] =~ s/(.*)(\(.*?\))\s*$/$1\.$2 (::)\}/; } # undouble GABC-Antiphone postprocess_ant($ant, $lang); $ant1 = ($version !~ /196/) ? $ant[0] : $ant; #difference between 1955 and 1960 setcomment($label, 'Source', $comment, $lang, $prefix); @@ -836,7 +852,11 @@ sub psalmi_minor { $p =~ s/[\[\]]//g; $p =~ s/[\(\-]/\,/g; $p =~ s /\)//; - push(@s, "\&psalm($p)"); + if ($lang =~ /gabc/i && $psalmTone) { + push (@s, "&psalm(\'$p,$psalmTone\')"); # GABC format: 'Psalmnumber,PsalmTone' + } else { + push(@s, "\&psalm($p)"); + } push(@s, "\n"); } @@ -867,15 +887,17 @@ sub psalmi_major { my $name = $hora; if ($hora =~ /Laudes/) { $name .= $laudes; } my @psalmi = splice(@psalmi, @psalmi); - - if ($version =~ /monastic/i) { + my @psalmTones; + + if ($version =~ /monastic/i && !($hora =~ /Laudes/i && $rule =~ /Matutinum romanum/i)) { # Triduum like Roman my $head = "Daym$dayofweek"; if ($hora =~ /Laudes/i) { if ($rule =~ /Psalmi Dominica/ || ($winner =~ /Sancti/i && $rank >= 4 && $dayname[1] !~ /vigil/i)) { $head = 'DaymF'; } if ($dayname[0] =~ /Pasc/i && $head =~ /Daym0/i) { $head = 'DaymP'; } } @psalmi = split("\n", $psalmi{"$head $hora"}); - + setbuild("Psalterium/Psalmi major", "$head $hora", 'Psalmi ord'); + if ($hora =~ /Laudes/i && $head =~ /Daym[1-6]/) { unless ( (($dayname[0] =~ /Adv|Quadp/) && ($duplex < 3) && ($commune !~ /C10/)) || (($dayname[0] =~ /Quad\d/) && ($dayname[1] =~ /Feria/)) @@ -895,6 +917,7 @@ sub psalmi_major { && !exists($winner{'Ant Laudes'})) { #ferial office @psalmi = split("\n", $psalmi{"Daya$dayofweek $name"}); + setbuild("Psalterium/Psalmi major", "Daya$dayofweek $name", 'Psalmi ord'); } elsif ($version =~ /trident/i) { my $dow = ($hora =~ /Laudes/i && $dayname[0] =~ /Pasc/i) @@ -904,12 +927,14 @@ sub psalmi_major { && $rule !~ /Feria/i) ? 'C' : $dayofweek; @psalmi = split("\n", $psalmi{"Daya$dow $name"}); + setbuild("Psalterium/Psalmi major", "Daya$dow $name", 'Psalmi ord'); } else { @psalmi = split("\n", $psalmi{"Day$dayofweek $name"}); + setbuild("Psalterium/Psalmi major", "Day$dayofweek $name", 'Psalmi ord'); } $comment = 0; $prefix = translate("Psalmi et antiphonae", $lang) . ' '; - setbuild("Psalterium/Psalmi major", "Day$dayofweek $name", 'Psalmi ord'); + my @antiphones; if (($hora =~ /Laudes/ || ($hora =~ /Vespera/ && $version =~ /Monastic/)) && $month == 12 && $day > 16 && $day < 24 && $dayofweek > 0) { @@ -965,6 +990,18 @@ sub psalmi_major { if ($antecapitulum) { $w = (columnsel($lang)) ? $antecapitulum : $antecapitulum2; } if ($w) { @antiphones = split("\n", $w); $comment = $c; } + if ($lang =~ /gabc/ && @antiphones) { + # strip Psalm Tones from Antiphones + foreach $myant (@antiphones) { + if ($myant =~ s/;;(.*);;(.*)/;;$1/ ) { + push (@psalmTones, $2); + $myant =~ s/;;\s*$//; + } else { + push (@psalmTones, ''); + } + } + } + #Psalmi de dominica if ( $version =~ /Trident/i && $testmode =~ /seasonal/i @@ -1002,7 +1039,8 @@ sub psalmi_major { if ($antiphones[4]) { # if 5 psalms and antiphones are given local($a1,$p1) = split(/;;/, $antiphones[3]); # split no. 4 local($a2,$p2) = split(/;;/, $antiphones[4]); # spilt no. 5 - $antiphones[3] = "$a2;;$p1" # and say antiphone 5 with psalm no. 4 + $antiphones[3] = "$a2;;$p1"; # and say antiphone 5 with psalm no. 4 + if (@psalmTones) { $psalmTones[3] = "$psalmTones[4]"; } # and use the Tone of the 5th antiphone } } @@ -1010,8 +1048,8 @@ sub psalmi_major { for ($i = 0; $i < $lim; $i++) { my $aflag = 0; $p = ($p[$i] =~ /;;(.*)/s) ? $1 : 'missing'; - - if ( $i == 4 + + if ( $i == 4 && $hora =~ /vespera/i && !$antecapitulum && $rule !~ /no Psalm5/i @@ -1026,13 +1064,27 @@ sub psalmi_major { setbuild2("Psalm5 = $p"); $aflag = 1; } - $psalmi[$i] = - ($antiphones[$i] =~ /\;\;[0-9\;\n]+/ && !$aflag) ? $antiphones[$i] - : ($antiphones[$i] =~ /(.*?);;/s) ? "$1;;$p" - : "$antiphones[$i];;$p"; + + if ($lang =~ /gabc/i ) { + # recombine antiphones with psalms and psalmtones according to antiphone + $p = ($p =~ /\'(.*),/s) ? $1 : $p; + + $p = ($antiphones[$i] =~ s/\;\;([0-9\;\n]+)// && !$aflag) ? $1 : $p; + my @p = split(';', $p); + foreach $p1 (@p) { + $p1 = "\'$p1,$psalmTones[$i]\'"; + } + $p = join(';', @p); + $psalmi[$i] = ($antiphones[$i] =~ /(.*?);;/s) ? "$1;;$p" : "$antiphones[$i];;$p"; + } else { + $psalmi[$i] = + ($antiphones[$i] =~ /\;\;[0-9\;\n]+/ && !$aflag) ? $antiphones[$i] + : ($antiphones[$i] =~ /(.*?);;/s) ? "$1;;$p" + : "$antiphones[$i];;$p"; + } } } - + if (alleluia_required($dayname[0], $votive) && (!exists($winner{"Ant $hora"}) || $commune =~ /C10/) && $communetype !~ /ex/i @@ -1050,7 +1102,7 @@ sub psalmi_major { $psalmi[3] =~ s/.*(?=;;)//; } } - + if (($dayname[0] =~ /(Adv|Quad)/i || emberday()) && $hora =~ /laudes/i && $version !~ /trident/i) { $prefix = "Laudes:$laudes $prefix"; } @@ -1071,6 +1123,7 @@ sub antetpsalm { my @line = split(';;', $line); my $ant = $line[0]; my @ant = split(/\s*\*\s*/, $ant); + if ($lang =~ /gabc/i && $ant =~ /\{.*\}/) { $ant[0] =~ s/(.*)(\(.*?\))\s*$/$1\.$2 (::)\}/; } # undouble antiphone postprocess_ant($ant, $lang); my $ant1 = ($duplex > 2 || $version =~ /196/) ? $ant : $ant[0]; #difference between 1995, 1960 @@ -1081,12 +1134,12 @@ sub antetpsalm { } my @p = split(';', $line[1]); - - for (my $i = 0; $i < @p; $i++) { + for (my $i = 0; $i < @p; $i++) { $p = $p[$i]; $p =~ s/[\(\-]/\,/g; $p =~ s/\)//; - if ($i < (@p - 1)) { $p = '-' . $p; } + if ($i < (@p - 1)) { $p = '-' . $p; } + $p =~ s/\-\'/\'\-/; # ensure dash behind apostrophe to be passed through to psalm script push(@s, "\&psalm($p)"); if ($i < (@p - 1)) { push(@s, "\n"); } } @@ -1607,6 +1660,10 @@ sub getcommemoratio { if (!$v) { $v = getfrompsalterium('Versum', $ind, $lang); } if (!$v) { $v = 'versus missing'; } postprocess_vr($v, $lang); + if ($lang =~/gabc/i) { + $v =~ s/\([a-zA-Z0-9\_\.\~\>\<\']+?\) \(::\)/\(f\.\) \(::\)/g; # Change Versicle into the simple tone + $v =~ s/\((?:hi|hr|h\_0|fe|f\_h|\,)\)/\(h\)/g; # More changes for solemn Versicle + } our %prayers; my $w = "!" . &translate("Commemoratio", $lang) . (($lang !~ /latin/i || $wday =~ /tempora/i) ? ':' : ''); # Adding : except for Latin Sancti which are in Genetiv $a =~ s/\s*\*\s*/ / unless ($version =~ /Monastic/i); @@ -2002,7 +2059,7 @@ sub doxology { { $dname = $1; } elsif (($month == 8 && $day > 15 && $day < 23 && $version !~ /Monastic/i) - || ($version != /1570/ && $month == 12 && $day > 8 && $day < 16 && $dayofweek > 0)) + || ($version !~ /1570/ && $month == 12 && $day > 8 && $day < 16 && $dayofweek > 0)) { $dname = 'Nat'; } else { diff --git a/web/cgi-bin/horas/specmatins.pl b/web/cgi-bin/horas/specmatins.pl index 4083d87cc26..19b45d76ed5 100644 --- a/web/cgi-bin/horas/specmatins.pl +++ b/web/cgi-bin/horas/specmatins.pl @@ -151,7 +151,7 @@ sub nocturn { pop(@s); push(@s, "Ant. $lastant", "\n"); - # versus cant be text or reference (number) + # versus can't be text or reference (number) my (@vs) = ($select[-1] =~ /^\d+$/ ? (@{$psalmi}[$select[-2]], @{$psalmi}[$select[-1]]) : ($select[-2], $select[-1])); process_inline_alleluias($vs[0]); process_inline_alleluias($vs[1]); @@ -219,8 +219,8 @@ sub psalmi_matutinum { } setbuild2("Subst Matutitunun Versus $name $dayofweek"); } - my ($w, $c) = getproprium('Ant Matutinum', $lang, 0, 1); + my ($w, $c) = getproprium('Ant Matutinum', $lang, 0, 1); if ($w) { @psalmi = split("\n", $w); $comment = $c; @@ -246,6 +246,22 @@ sub psalmi_matutinum { } } + if ($lang =~/gabc/i) { + foreach my $psalmline (@psalmi) { + my @a = split(';;', $psalmline); # retrieve psalmtone behind second ;; + if (@a > 2) { + my $ant0 = chompd($a[0]); + my @psalm0 = split(';', chompd($a[1])); + my $psalmTone = chompd($a[2]); + foreach my $ps0 (@psalm0) { + $ps0 = "'$ps0,$psalmTone'"; # combine psalm tone with all psalms + } + my $psalm0 = join(';', @psalm0); + $psalmline = "$ant0;;$psalm0"; # recombine antiphone line + } + } + } + if ( $version =~ /Trident/i && $testmode =~ /seasonal/i && $winner =~ /Sancti/i @@ -267,16 +283,14 @@ sub psalmi_matutinum { if ($rule =~ /9 lectio/i && !$ltype1960 && $rank >= 2 && !($version =~ /trident/i && $winner{Rank} =~ /Dominica/i && $dayofweek>0)) { setbuild2("9 lectiones"); - if ($dayname[0] =~ /Pasc/i && !exists($winner{'Ant Matutinum'}) && $rank < 5) { #??? ex + if ($dayname[0] =~ /Pasc/i && !exists($winner{'Ant Matutinum'}) && $rank < 5) { # Paschal tide my $dname = ($winner{Rank} =~ /Dominica/i) ? 'Dominica' : 'Feria'; @spec = split("\n", $spec{"Pasc Ant $dname"}); - foreach my $i (3, 4, 8, 9, 13, 14) { $psalmi[$i] = $spec[$i]; } - } elsif ($winner =~ /tempora/i - && $dayname[0] =~ /(Adv|Quad|Pasc)/i - && !exists($winner{'Ant Matutinum'})) + foreach my $i (3, 4, 8, 9, 13, 14) { $psalmi[$i] = $spec[$i]; } # replace Versicles at Nocturns + } elsif ($winner =~ /tempora/i && $dayname[0] =~ /(Adv|Quad|Pasc)/i && !exists($winner{'Ant Matutinum'})) # Advent, Quad, and Paschaltide { - $tmp = $1; - if ($dayname[0] =~ /(Quad5|Quad6)/) { $tmp = 'Quad5'; } + $tmp = $1; # Adv or Quad or Pasc + if ($dayname[0] =~ /(Quad5|Quad6)/) { $tmp = 'Quad5'; } # change for Passiontide @spec = split("\n", $spec{"$tmp 1 Versum"}); if (@spec) { $psalmi[3] = $spec[0]; $psalmi[4] = $spec[1]; } @spec = split("\n", $spec{"$tmp 2 Versum"}); @@ -456,7 +470,7 @@ sub lectiones { if ($rule !~ /Limit.*?Benedictio/i) { push(@s, "\&pater_noster"); } else { - push(@s, "\$Pater noster"); + push(@s, "\$Pater totum secreto"); } my %benedictio = %{setupstring($lang, 'Psalterium/Benedictions.txt')}; my $i = $num; @@ -508,8 +522,8 @@ sub lectiones { #absolutiones if ($rule !~ /Limit.*?Benedictio/i) { push(@s, "Absolutio. $a[0]"); - push(@s, "\n"); } + push(@s, "\n"); # if 1960 or monastic of ferial type diverge to sub routine my $ltype1960 = gettype1960(); @@ -1219,21 +1233,18 @@ sub responsory_gloria { my $flag = 0; my $read_per_noct = ($rule =~ /12 lectio/) ? 4 : 3; - if ( - ($num % $read_per_noct == 0) - || ($rule =~ /9 lectiones/i && ($winner !~ /tempora/i || $dayname[0] !~ /(Adv|Quad)/i) && $num == 8) - || ( $version =~ /1960/ - && $rule =~ /9 lectiones/i - && $rule =~ /Feria Te Deum/i - && $num == 2 - && ($dayname[0] !~ /quad/i)) - || (gettype1960() > 1 && $num == 2 && $winner !~ /C12/) - || ($rank < 2 && $num == 2 && $winner =~ /(Sancti)/) - || ($num == 2 && $winner =~ /C10/) - || ($num == 2 && ($rule =~ /Feria Te Deum/i || $dayname[0] =~ /Pasc[07]/i) && $rule !~ /9 lectiones/i) - ) - { - if ($w !~ /\&Gloria/i) { + if (($num % $read_per_noct == 0) # we are at the last Lesson of the Nocturn + || ($rule =~ /9 lectiones/i && ($winner !~ /tempora/i || $dayname[0] !~ /(Adv|Quad)/i) && $num == 8) # or at the 8th Lesson with Te Deum + || ( $version =~ /1960/ && $rule =~ /9 lectiones/i && $rule =~ /Feria Te Deum/i + && $num == 2 && ($dayname[0] !~ /quad/i)) # or at the 2nd Lesson at a 1960s with Te Deum + || (gettype1960() > 1 && $num == 2 && $winner !~ /C12/) + || ($rank < 2 && $num == 2 && $winner =~ /(Sancti)/) # or a simple Matins at the 2nd + || ($num == 2 && $winner =~ /C10/) # or at BMV in Sabbato + || ($num == 2 && ($rule =~ /Feria Te Deum/i || $dayname[0] =~ /Pasc[07]/i) && $rule !~ /9 lectiones/i)) { # let's add the Gloria + if ($lang =~ /gabc/ && $w =~ /\{.*\}/) { + if ($w =~ /\_\s\{gabc:/) { $w =~ s/\_\s\{gabc:(.*)\}/\_ \{gabc:$1-gloria\}/; } # choose Responsory with Gloria #TODO: check T.P.! + + } elsif ($w !~ /\&Gloria/i) { $w =~ s/[\s_]*$//gs; $line = ($w =~ /(R\..*?$)/) ? $1 : ''; $w .= "\n\&Gloria1\n$line"; diff --git a/web/www/horas/horas.dialog b/web/www/horas/horas.dialog index 2af4c8b763e..542f72d5685 100644 --- a/web/www/horas/horas.dialog +++ b/web/www/horas/horas.dialog @@ -31,7 +31,7 @@ Language~>$langc~>Optionmenu~>languages;; Votive~>$votive~>Optionmenu~>votives;; [languages] -Latin,Dansk,Deutsch,English,Español/Espanol,Français/Francais,Italiano,Magyar,Polski,Português/Portugues,Latin-Bea,Polski-Newer +Latin,Dansk,Deutsch,English,Español/Espanol,Français/Francais,Italiano,Magyar,Polski,Português/Portugues,Latin-Bea,Polski-Newer,Latin-gabc [versions] Tridentine - 1570,Tridentine - 1888,Tridentine - 1906,Divino Afflatu - 1954,Reduced - 1955,Rubrics 1960 - 1960,Rubrics 1960 - 2020 USA,Monastic - 1963,Ordo Praedicatorum - 1962