From 5e202299250d3f96261deecc0ad094e32ebe0ae6 Mon Sep 17 00:00:00 2001 From: STEPHANVS Date: Sun, 4 Jul 2021 18:02:22 +0200 Subject: [PATCH 01/21] Support for more complex chords; have chordless songs in
--- openlp/core/display/render.py | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/openlp/core/display/render.py b/openlp/core/display/render.py index 5efd7577e..86b74b3eb 100644 --- a/openlp/core/display/render.py +++ b/openlp/core/display/render.py @@ -44,13 +44,15 @@ from openlp.core.lib.formattingtags import FormattingTags log = logging.getLogger(__name__) -ENGLISH_NOTES = '[CDEFGAB]' -GERMAN_NOTES = '[CDEFGAH]' -NEOLATIN_NOTES = '(Do|Re|Mi|Fa|Sol|La|Si)' -CHORD_SUFFIXES = '(b|bb)?(#)?(m|maj7|maj|min7|min|sus)?(1|2|3|4|5|6|7|8|9)?' +ENGLISH_NOTES = '[CDEFGAB]?' +GERMAN_NOTES = '[CDEFGABH]?' +NEOLATIN_NOTES = '(Do|Re|Mi|Fa|Sol|La|Si)?' +CHORD_PREFIXES = '(=|\(|\|)*?' +CHORD_SUFFIXES = '(b|bb|#|##|x|-|m|maj|min|sus|dim|0|1|2|3|4|5|6|7|8|9|\))*?' SLIM_CHARS = 'fiíIÍjlĺľrtť.,;/ ()|"\'!:\\' CHORD_TEMPLATE = '{chord}' -FIRST_CHORD_TEMPLATE = '{chord}' +FIRST_CHORD_TEMPLATE = '{chord}' +NO_CHORD_TEMPLATE = '{chord}' CHORD_LINE_TEMPLATE = '{chord}{tail}{whitespace}{remainder}' WHITESPACE_TEMPLATE = '{whitespaces}' VERSE = 'The Lord said to {r}Noah{/r}: \n' \ @@ -78,8 +80,8 @@ def _construct_chord_regex(notes): :param notes: The regular expression for a set of valid notes :return: An expanded regular expression for valid chords """ - chord = notes + CHORD_SUFFIXES - return '(' + chord + '(/' + chord + ')?)' + #chord = CHORD_PREFIXES + notes + CHORD_SUFFIXES + return '(' + CHORD_PREFIXES + notes + CHORD_SUFFIXES + '(/' + notes + CHORD_SUFFIXES + ')?)' def _construct_chord_match(notes): @@ -186,11 +188,11 @@ def render_chords_in_line(match): # The actual chord, would be "G" in match "[G]sweet the " chord = match.group(1) # The tailing word of the chord, would be "sweet" in match "[G]sweet the " - tail = match.group(11) + tail = match.group(6) # The remainder of the line, until line end or next chord. Would be " the " in match "[G]sweet the " - remainder = match.group(12) + remainder = match.group(7) # Line end if found, else None - end = match.group(13) + end = match.group(8) # Based on char width calculate width of chord for chord_char in chord: if chord_char not in SLIM_CHARS: @@ -268,7 +270,10 @@ def render_chords(text): rendered_lines.append(new_line) else: chords_on_prev_line = False - rendered_lines.append(html.escape(line)) + #rendered_lines.append(html.escape(line)) + chord_template = NO_CHORD_TEMPLATE + new_line = chord_template.format(chord=line) + rendered_lines.append(new_line) return '{br}'.join(rendered_lines) From f41f8a72c170eb9eaa879b4f599f1455e8157ae8 Mon Sep 17 00:00:00 2001 From: STEPHANVS Date: Sun, 4 Jul 2021 18:12:19 +0200 Subject: [PATCH 02/21] Fix tests --- tests/openlp_core/lib/test_serviceitem.py | 30 ++++++++++++++--------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/tests/openlp_core/lib/test_serviceitem.py b/tests/openlp_core/lib/test_serviceitem.py index 7b2de8aaf..15ef57dce 100644 --- a/tests/openlp_core/lib/test_serviceitem.py +++ b/tests/openlp_core/lib/test_serviceitem.py @@ -725,10 +725,11 @@ def test_to_dict_text_item(state_media, settings, service_item_env): 'notes': '', 'slides': [ { - 'chords': 'Amazing Grace! how sweet the sound\n' + 'chords': '' + 'Amazing Grace! how sweet the sound\n' 'That saved a wretch like me;\n' 'I once was lost, but now am found,\n' - 'Was blind, but now I see.', + 'Was blind, but now I see.', 'html': 'Amazing Grace! how sweet the sound\n' 'That saved a wretch like me;\n' 'I once was lost, but now am found,\n' @@ -743,10 +744,11 @@ def test_to_dict_text_item(state_media, settings, service_item_env): 'footer': 'Amazing Grace
Written by: John Newton' }, { - 'chords': '’Twas grace that taught my heart to fear,\n' + 'chords': '' + '’Twas grace that taught my heart to fear,\n' 'And grace my fears relieved;\n' 'How precious did that grace appear,\n' - 'The hour I first believed!', + 'The hour I first believed!', 'html': '’Twas grace that taught my heart to fear,\n' 'And grace my fears relieved;\n' 'How precious did that grace appear,\n' @@ -761,10 +763,11 @@ def test_to_dict_text_item(state_media, settings, service_item_env): 'footer': 'Amazing Grace
Written by: John Newton' }, { - 'chords': 'Through many dangers, toils and snares\n' + 'chords': '' + 'Through many dangers, toils and snares\n' 'I have already come;\n' '’Tis grace that brought me safe thus far,\n' - 'And grace will lead me home.', + 'And grace will lead me home.', 'html': 'Through many dangers, toils and snares\n' 'I have already come;\n' '’Tis grace that brought me safe thus far,\n' @@ -779,10 +782,11 @@ def test_to_dict_text_item(state_media, settings, service_item_env): 'footer': 'Amazing Grace
Written by: John Newton' }, { - 'chords': 'The Lord has promised good to me,\n' + 'chords': '' + 'The Lord has promised good to me,\n' 'His word my hope secures;\n' 'He will my shield and portion be\n' - 'As long as life endures.', + 'As long as life endures.', 'html': 'The Lord has promised good to me,\n' 'His word my hope secures;\n' 'He will my shield and portion be\n' @@ -797,10 +801,11 @@ def test_to_dict_text_item(state_media, settings, service_item_env): 'footer': 'Amazing Grace
Written by: John Newton' }, { - 'chords': 'Yes, when this heart and flesh shall fail,\n' + 'chords': '' + 'Yes, when this heart and flesh shall fail,\n' 'And mortal life shall cease,\n' 'I shall possess within the veil\n' - 'A life of joy and peace.', + 'A life of joy and peace.', 'html': 'Yes, when this heart and flesh shall fail,\n' 'And mortal life shall cease,\n' 'I shall possess within the veil\n' @@ -815,10 +820,11 @@ def test_to_dict_text_item(state_media, settings, service_item_env): 'footer': 'Amazing Grace
Written by: John Newton' }, { - 'chords': 'When we’ve been there a thousand years,\n' + 'chords': '' + 'When we’ve been there a thousand years,\n' 'Bright shining as the sun,\n' 'We’ve no less days to sing God’s praise\n' - 'Than when we first begun.', + 'Than when we first begun.', 'html': 'When we’ve been there a thousand years,\n' 'Bright shining as the sun,\n' 'We’ve no less days to sing God’s praise\n' From 9f5dce42bd64efc25f88fedf22d22a98c4373309 Mon Sep 17 00:00:00 2001 From: STEPHANVS Date: Sun, 4 Jul 2021 18:18:06 +0200 Subject: [PATCH 03/21] Fix more tests --- tests/openlp_core/display/test_render.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/openlp_core/display/test_render.py b/tests/openlp_core/display/test_render.py index 25b3aa624..40ddee4aa 100644 --- a/tests/openlp_core/display/test_render.py +++ b/tests/openlp_core/display/test_render.py @@ -122,7 +122,7 @@ def test_render_chords_with_special_chars(settings): text_with_rendered_chords = render_tags(text_with_chords, can_render_chords=True) # THEN: We should get html that looks like below - expected_html = 'ID' \ + expected_html = 'ID' \ ''M NOT MOVED BY WHAT I SEE HALLEF' \ 'LUJACH' assert text_with_rendered_chords == expected_html, 'The rendered chords should look as expected' From 41344390f56df74f473612ad3e1f9fb416a396a1 Mon Sep 17 00:00:00 2001 From: STEPHANVS Date: Sun, 4 Jul 2021 18:33:18 +0200 Subject: [PATCH 04/21] Even more test fixes --- openlp/core/display/render.py | 8 ++++---- tests/openlp_core/display/test_render.py | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/openlp/core/display/render.py b/openlp/core/display/render.py index 86b74b3eb..0cd6a6b4d 100644 --- a/openlp/core/display/render.py +++ b/openlp/core/display/render.py @@ -47,8 +47,8 @@ log = logging.getLogger(__name__) ENGLISH_NOTES = '[CDEFGAB]?' GERMAN_NOTES = '[CDEFGABH]?' NEOLATIN_NOTES = '(Do|Re|Mi|Fa|Sol|La|Si)?' -CHORD_PREFIXES = '(=|\(|\|)*?' -CHORD_SUFFIXES = '(b|bb|#|##|x|-|m|maj|min|sus|dim|0|1|2|3|4|5|6|7|8|9|\))*?' +CHORD_PREFIXES = '(=|\\(|\\|)*?' +CHORD_SUFFIXES = '(b|bb|#|##|x|-|m|maj|min|sus|dim|0|1|2|3|4|5|6|7|8|9|\\))*?' SLIM_CHARS = 'fiíIÍjlĺľrtť.,;/ ()|"\'!:\\' CHORD_TEMPLATE = '{chord}' FIRST_CHORD_TEMPLATE = '{chord}' @@ -80,7 +80,7 @@ def _construct_chord_regex(notes): :param notes: The regular expression for a set of valid notes :return: An expanded regular expression for valid chords """ - #chord = CHORD_PREFIXES + notes + CHORD_SUFFIXES + # chord = CHORD_PREFIXES + notes + CHORD_SUFFIXES return '(' + CHORD_PREFIXES + notes + CHORD_SUFFIXES + '(/' + notes + CHORD_SUFFIXES + ')?)' @@ -270,7 +270,7 @@ def render_chords(text): rendered_lines.append(new_line) else: chords_on_prev_line = False - #rendered_lines.append(html.escape(line)) + # rendered_lines.append(html.escape(line)) chord_template = NO_CHORD_TEMPLATE new_line = chord_template.format(chord=line) rendered_lines.append(new_line) diff --git a/tests/openlp_core/display/test_render.py b/tests/openlp_core/display/test_render.py index 40ddee4aa..2ff35181a 100644 --- a/tests/openlp_core/display/test_render.py +++ b/tests/openlp_core/display/test_render.py @@ -104,7 +104,7 @@ def test_render_chords(settings): text_with_rendered_chords = render_chords(text_with_chords) # THEN: We should get html that looks like below - expected_html = 'HC' \ + expected_html = 'HC' \ 'alleluya.F' \ '   G/B' assert text_with_rendered_chords == expected_html, 'The rendered chords should look as expected' From 0fc81b8efbc3991c508a3be2fe58f492f3f63688 Mon Sep 17 00:00:00 2001 From: STEPHANVS Date: Mon, 5 Jul 2021 15:43:32 +0200 Subject: [PATCH 05/21] Support "add" in chord suffix, support song key definition with "=" --- openlp/core/display/render.py | 2 +- openlp/plugins/songs/lib/__init__.py | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/openlp/core/display/render.py b/openlp/core/display/render.py index 0cd6a6b4d..9eb7abbe6 100644 --- a/openlp/core/display/render.py +++ b/openlp/core/display/render.py @@ -48,7 +48,7 @@ ENGLISH_NOTES = '[CDEFGAB]?' GERMAN_NOTES = '[CDEFGABH]?' NEOLATIN_NOTES = '(Do|Re|Mi|Fa|Sol|La|Si)?' CHORD_PREFIXES = '(=|\\(|\\|)*?' -CHORD_SUFFIXES = '(b|bb|#|##|x|-|m|maj|min|sus|dim|0|1|2|3|4|5|6|7|8|9|\\))*?' +CHORD_SUFFIXES = '(b|bb|#|##|x|-|m|maj|min|sus|dim|add|0|1|2|3|4|5|6|7|8|9|\\))*?' SLIM_CHARS = 'fiíIÍjlĺľrtť.,;/ ()|"\'!:\\' CHORD_TEMPLATE = '{chord}' FIRST_CHORD_TEMPLATE = '{chord}' diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index 0969b4d3f..16d1b5cb7 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -640,6 +640,12 @@ def transpose_chord(chord, transpose_value, notation): current_chord = current_chord[1:] else: current_chord = '' + if current_chord and current_chord[0] == '=': + transposed_chord += '=' + if len(current_chord) > 1: + current_chord = current_chord[1:] + else: + current_chord = '' if len(current_chord) > 0: if len(current_chord) > 1: if '#b'.find(current_chord[1]) == -1: From b5d2908c15d3b4026b775270bbc655d6fcaa8f5d Mon Sep 17 00:00:00 2001 From: STEPHANVS Date: Wed, 7 Jul 2021 10:56:19 +0200 Subject: [PATCH 06/21] Additional notes and suffixes fix --- openlp/core/display/render.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openlp/core/display/render.py b/openlp/core/display/render.py index 9eb7abbe6..eb19a17ae 100644 --- a/openlp/core/display/render.py +++ b/openlp/core/display/render.py @@ -44,11 +44,11 @@ from openlp.core.lib.formattingtags import FormattingTags log = logging.getLogger(__name__) -ENGLISH_NOTES = '[CDEFGAB]?' -GERMAN_NOTES = '[CDEFGABH]?' -NEOLATIN_NOTES = '(Do|Re|Mi|Fa|Sol|La|Si)?' +ENGLISH_NOTES = '(C|D|E|F|G|A|B|N.C.)?' +GERMAN_NOTES = '(C|D|E|F|G|A|B|H|N.C.)?' +NEOLATIN_NOTES = '(Do|Re|Mi|Fa|Sol|La|Si|N.C.)?' CHORD_PREFIXES = '(=|\\(|\\|)*?' -CHORD_SUFFIXES = '(b|bb|#|##|x|-|m|maj|min|sus|dim|add|0|1|2|3|4|5|6|7|8|9|\\))*?' +CHORD_SUFFIXES = '(b|#|x|+|-|M|m|Maj|maj|min|sus|dim|add|aug|dom|0|1|2|3|4|5|6|7|8|9|\\(|\\)|no|omit)*?' SLIM_CHARS = 'fiíIÍjlĺľrtť.,;/ ()|"\'!:\\' CHORD_TEMPLATE = '{chord}' FIRST_CHORD_TEMPLATE = '{chord}' From 3c60e9aaf8a4ce72af08313c51cb3f3168afb99a Mon Sep 17 00:00:00 2001 From: STEPHANVS Date: Wed, 7 Jul 2021 11:07:18 +0200 Subject: [PATCH 07/21] nothing to repeat issue? --- openlp/core/display/render.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/display/render.py b/openlp/core/display/render.py index eb19a17ae..2b3d206d9 100644 --- a/openlp/core/display/render.py +++ b/openlp/core/display/render.py @@ -48,7 +48,7 @@ ENGLISH_NOTES = '(C|D|E|F|G|A|B|N.C.)?' GERMAN_NOTES = '(C|D|E|F|G|A|B|H|N.C.)?' NEOLATIN_NOTES = '(Do|Re|Mi|Fa|Sol|La|Si|N.C.)?' CHORD_PREFIXES = '(=|\\(|\\|)*?' -CHORD_SUFFIXES = '(b|#|x|+|-|M|m|Maj|maj|min|sus|dim|add|aug|dom|0|1|2|3|4|5|6|7|8|9|\\(|\\)|no|omit)*?' +CHORD_SUFFIXES = '(b|bb|#|##|x|+|-|M|m|Maj|maj|min|sus|dim|add|aug|dom|0|1|2|3|4|5|6|7|8|9|\\(|\\)|no|omit)*?' SLIM_CHARS = 'fiíIÍjlĺľrtť.,;/ ()|"\'!:\\' CHORD_TEMPLATE = '{chord}' FIRST_CHORD_TEMPLATE = '{chord}' From 4d70d0274004dea67063a2380688e8e78e1b8c99 Mon Sep 17 00:00:00 2001 From: STEPHANVS Date: Wed, 7 Jul 2021 11:13:13 +0200 Subject: [PATCH 08/21] Revert "nothing to repeat issue?" This reverts commit 3c60e9aaf8a4ce72af08313c51cb3f3168afb99a. --- openlp/core/display/render.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/display/render.py b/openlp/core/display/render.py index 2b3d206d9..eb19a17ae 100644 --- a/openlp/core/display/render.py +++ b/openlp/core/display/render.py @@ -48,7 +48,7 @@ ENGLISH_NOTES = '(C|D|E|F|G|A|B|N.C.)?' GERMAN_NOTES = '(C|D|E|F|G|A|B|H|N.C.)?' NEOLATIN_NOTES = '(Do|Re|Mi|Fa|Sol|La|Si|N.C.)?' CHORD_PREFIXES = '(=|\\(|\\|)*?' -CHORD_SUFFIXES = '(b|bb|#|##|x|+|-|M|m|Maj|maj|min|sus|dim|add|aug|dom|0|1|2|3|4|5|6|7|8|9|\\(|\\)|no|omit)*?' +CHORD_SUFFIXES = '(b|#|x|+|-|M|m|Maj|maj|min|sus|dim|add|aug|dom|0|1|2|3|4|5|6|7|8|9|\\(|\\)|no|omit)*?' SLIM_CHARS = 'fiíIÍjlĺľrtť.,;/ ()|"\'!:\\' CHORD_TEMPLATE = '{chord}' FIRST_CHORD_TEMPLATE = '{chord}' From 97c28031c2200611916e68a2135c7e6207bb4a0c Mon Sep 17 00:00:00 2001 From: STEPHANVS Date: Wed, 7 Jul 2021 11:13:54 +0200 Subject: [PATCH 09/21] fix CHORD_SUFFIXES --- openlp/core/display/render.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openlp/core/display/render.py b/openlp/core/display/render.py index eb19a17ae..fead88e0b 100644 --- a/openlp/core/display/render.py +++ b/openlp/core/display/render.py @@ -48,7 +48,7 @@ ENGLISH_NOTES = '(C|D|E|F|G|A|B|N.C.)?' GERMAN_NOTES = '(C|D|E|F|G|A|B|H|N.C.)?' NEOLATIN_NOTES = '(Do|Re|Mi|Fa|Sol|La|Si|N.C.)?' CHORD_PREFIXES = '(=|\\(|\\|)*?' -CHORD_SUFFIXES = '(b|#|x|+|-|M|m|Maj|maj|min|sus|dim|add|aug|dom|0|1|2|3|4|5|6|7|8|9|\\(|\\)|no|omit)*?' +CHORD_SUFFIXES = '(b|#|x|\\+|-|M|m|Maj|maj|min|sus|dim|add|aug|dom|0|1|2|3|4|5|6|7|8|9|\\(|\\)|no|omit)*?' SLIM_CHARS = 'fiíIÍjlĺľrtť.,;/ ()|"\'!:\\' CHORD_TEMPLATE = '{chord}' FIRST_CHORD_TEMPLATE = '{chord}' From b9ef947cb083b1080094f68461ce334d3822394f Mon Sep 17 00:00:00 2001 From: STEPHANVS Date: Wed, 7 Jul 2021 11:26:34 +0200 Subject: [PATCH 10/21] regex fixes, NEOLATIN_NOTES would introduce an extra capturing group, while ENGLISH_NOTES and GERMAN_NOTES would not --- openlp/core/display/render.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openlp/core/display/render.py b/openlp/core/display/render.py index fead88e0b..33555bc31 100644 --- a/openlp/core/display/render.py +++ b/openlp/core/display/render.py @@ -44,9 +44,9 @@ from openlp.core.lib.formattingtags import FormattingTags log = logging.getLogger(__name__) -ENGLISH_NOTES = '(C|D|E|F|G|A|B|N.C.)?' -GERMAN_NOTES = '(C|D|E|F|G|A|B|H|N.C.)?' -NEOLATIN_NOTES = '(Do|Re|Mi|Fa|Sol|La|Si|N.C.)?' +ENGLISH_NOTES = '(C|D|E|F|G|A|B|N\\.C\\.)?' +GERMAN_NOTES = '(C|D|E|F|G|A|B|H|N\\.C\\.)?' +NEOLATIN_NOTES = '(Do|Re|Mi|Fa|Sol|La|Si|N\\.C\\.)?' CHORD_PREFIXES = '(=|\\(|\\|)*?' CHORD_SUFFIXES = '(b|#|x|\\+|-|M|m|Maj|maj|min|sus|dim|add|aug|dom|0|1|2|3|4|5|6|7|8|9|\\(|\\)|no|omit)*?' SLIM_CHARS = 'fiíIÍjlĺľrtť.,;/ ()|"\'!:\\' @@ -188,11 +188,11 @@ def render_chords_in_line(match): # The actual chord, would be "G" in match "[G]sweet the " chord = match.group(1) # The tailing word of the chord, would be "sweet" in match "[G]sweet the " - tail = match.group(6) + tail = match.group(8) # The remainder of the line, until line end or next chord. Would be " the " in match "[G]sweet the " - remainder = match.group(7) + remainder = match.group(9) # Line end if found, else None - end = match.group(8) + end = match.group(10) # Based on char width calculate width of chord for chord_char in chord: if chord_char not in SLIM_CHARS: From 32afafce72212291a740f1f10e276a21615f2c95 Mon Sep 17 00:00:00 2001 From: STEPHANVS Date: Thu, 8 Jul 2021 10:36:19 +0200 Subject: [PATCH 11/21] Support "|" as "barline" in chords layer --- openlp/plugins/songs/lib/__init__.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index 16d1b5cb7..6fdfa89b7 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -646,6 +646,12 @@ def transpose_chord(chord, transpose_value, notation): current_chord = current_chord[1:] else: current_chord = '' + if current_chord and current_chord[0] == '|': + transposed_chord += '|' + if len(current_chord) > 1: + current_chord = current_chord[1:] + else: + current_chord = '' if len(current_chord) > 0: if len(current_chord) > 1: if '#b'.find(current_chord[1]) == -1: From 7d3f5eab9cff463cf04074c1bf2542dedd9dbf95 Mon Sep 17 00:00:00 2001 From: STEPHANVS Date: Thu, 22 Jul 2021 22:03:55 +0200 Subject: [PATCH 12/21] Chord transpose rework, works on verse_edit_all --- openlp/plugins/songs/forms/editverseform.py | 2 +- openlp/plugins/songs/lib/__init__.py | 247 +++++++++++++++----- 2 files changed, 193 insertions(+), 56 deletions(-) diff --git a/openlp/plugins/songs/forms/editverseform.py b/openlp/plugins/songs/forms/editverseform.py index c046c3a03..710ae3785 100644 --- a/openlp/plugins/songs/forms/editverseform.py +++ b/openlp/plugins/songs/forms/editverseform.py @@ -233,7 +233,7 @@ class EditVerseForm(QtWidgets.QDialog, Ui_EditVerseDialog): """ if Registry().get('settings').value('songs/enable chords'): try: - transpose_lyrics(self.verse_text_edit.toPlainText(), 1) + transpose_lyrics(self.verse_text_edit.toPlainText(), 0) super(EditVerseForm, self).accept() except ValueError as ve: # Transposing failed diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index 6fdfa89b7..83d2354ca 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -559,15 +559,17 @@ def transpose_lyrics(lyrics, transpose_value): verse_list = re.split(r'(---\[.+?:.+?\]---|\[---\])', lyrics) transposed_lyrics = '' notation = Registry().get('settings').value('songs/chord notation') + key = None for verse in verse_list: if verse.startswith('---[') or verse == '[---]': transposed_lyrics += verse else: - transposed_lyrics += transpose_verse(verse, transpose_value, notation) + transposed_lyric, key = transpose_verse(verse, transpose_value, notation, key) + transposed_lyrics += transposed_lyric return transposed_lyrics -def transpose_verse(verse_text, transpose_value, notation): +def transpose_verse(verse_text, transpose_value, notation, key): """ Transpose Verse @@ -577,10 +579,13 @@ def transpose_verse(verse_text, transpose_value, notation): :return: The transposed lyrics """ if '[' not in verse_text: - return verse_text - # Split the lyrics based on chord tags + return verse_text, key + # Split the lyrics based on chord tags, based on this, chords and bass will be treated equally and separately, + # 6/9 chords should be noted 6-9 or 69 or 6add9 lyric_list = re.split(r'(\[|\]|/)', verse_text) transposed_lyrics = '' + isbass = False + lastchord = None in_tag = False for word in lyric_list: if not in_tag: @@ -591,19 +596,24 @@ def transpose_verse(verse_text, transpose_value, notation): if word == ']': in_tag = False transposed_lyrics += word - elif word == '/' or word == '--}{--': + elif word == '/': + isbass = True + transposed_lyrics += word + elif word == '--}{--': transposed_lyrics += word else: # This MUST be a chord - transposed_lyrics += transpose_chord(word, transpose_value, notation) + transposed_chord, key, lastchord = transpose_chord(word, transpose_value, notation, key, lastchord, isbass) + isbass = False + transposed_lyrics += transposed_chord # If still inside a chord tag something is wrong! if in_tag: - return verse_text + return verse_text, key else: - return transposed_lyrics + return transposed_lyrics, key -def transpose_chord(chord, transpose_value, notation): +def transpose_chord(chord, transpose_value, notation, key, lastchord, isbass): """ Transpose chord according to the notation used. NOTE: This function has a javascript equivalent in chords.js - make sure to update both! @@ -624,59 +634,186 @@ def transpose_chord(chord, transpose_value, notation): 'english': ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B'], 'neo-latin': ['Do', 'Reb', 'Re', 'Mib', 'Fab', 'Fa', 'Solb', 'Sol', 'Lab', 'La', 'Sib', 'Si'] } - chord_split = chord.replace('♭', 'b').split('/') + scales = { + 'german': { + 'C' : ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'B', 'H'], + 'Am' : ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'B', 'H'], + 'C#' : ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'H'], + 'A#m' : ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'H'], + 'Db' : ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bb', 'B', 'Cb'], + 'Bm' : ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bb', 'B', 'Cb'], + 'D' : ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'B', 'H'], + 'Hm' : ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'B', 'H'], + 'D#' : ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'H'], + 'H#m' : ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'H'], + 'Eb' : ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bb', 'B', 'Cb'], + 'Cm' : ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bb', 'B', 'Cb'], + 'E' : ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'B', 'H'], + 'C#m' : ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'B', 'H'], + 'F' : ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'B', 'Cb'], + 'Dm' : ['C', 'C#', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'B', 'H'], + 'F#' : ['C', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'H'], + 'D#m' : ['C', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'H'], + 'Gb' : ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bb', 'B', 'Cb'], + 'Ebm' : ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bb', 'B', 'Cb'], + 'G' : ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'B', 'H'], + 'Em' : ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'B', 'H'], + 'G#' : ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'H'], + 'E#m' : ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'H'], + 'Ab' : ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bb', 'B', 'Cb'], + 'Fm' : ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bb', 'B', 'Cb'], + 'A' : ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'G#', 'A', 'B', 'H'], + 'F#m' : ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'G#', 'A', 'B', 'H'], + 'A#' : ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'Gx', 'A#', 'H'], + 'F##m' : ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'Gx', 'A#', 'H'], + 'Fxm' : ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'Gx', 'A#', 'H'], + 'B' : ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'A', 'B', 'Cb'], + 'Gm' : ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'A', 'B', 'Cb'], + 'H' : ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'H'], + 'G#m' : ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'H'], + 'Cb' : ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'Gbb', 'Gb', 'Abb', 'Ab', 'Bb', 'B', 'Cb'], + 'Abm' : ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'Gbb', 'Gb', 'Abb', 'Ab', 'Bb', 'B', 'Cb'] + }, + 'english': { + 'C' : ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], + 'Am' : ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], + 'C#' : ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'B'], + 'A#m' : ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'B'], + 'Db' : ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'], + 'Bm' : ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'], + 'D' : ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], + 'Hm' : ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], + 'D#' : ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'B'], + 'H#m' : ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'B'], + 'Eb' : ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bbb', 'Bb', 'Cb'], + 'Cm' : ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bbb', 'Bb', 'Cb'], + 'E' : ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'Bb', 'B'], + 'C#m' : ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'Bb', 'B'], + 'F' : ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'Cb'], + 'Dm' : ['C', 'C#', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B'], + 'F#' : ['C', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'B'], + 'D#m' : ['C', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'B'], + 'Gb' : ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'], + 'Ebm' : ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'], + 'G' : ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], + 'Em' : ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], + 'G#' : ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'B'], + 'E#m' : ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'B'], + 'Ab' : ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bbb', 'Bb', 'Cb'], + 'Fm' : ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bbb', 'Bb', 'Cb'], + 'A' : ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'G#', 'A', 'Bb', 'B'], + 'F#m' : ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'G#', 'A', 'Bb', 'B'], + 'A#' : ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'Gx', 'A#', 'B'], + 'F##m' : ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'Gx', 'A#', 'B'], + 'Fxm' : ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'Gx', 'A#', 'B'], + 'B' : ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'Cb'], + 'Gm' : ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'Cb'], + 'H' : ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'], + 'G#m' : ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'], + 'Cb' : ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'Gbb', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'], + 'Abm' : ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'Gbb', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'] + } + } + notenumbers = { + 'german': { + 'C' : 0, 'H#' : 0, 'B##' : 0, 'Bx' : 0, 'Dbb' : 0, + 'C#' : 1, 'Db' : 1, + 'D' : 2, 'C##' : 2, 'Cx' : 2, 'Ebb' : 2, + 'D#' : 3, 'Eb' : 3, + 'E' : 4, 'D##' : 4, 'Dx' : 4, 'Fb' : 4, + 'F' : 5, 'E#' : 5, 'Gbb' : 5, + 'F#' : 6, 'Gb' : 6, + 'G' : 7, 'F##' : 7, 'Fx' : 7, 'Abb' : 7, + 'G#' : 8, 'Ab' : 8, + 'A' : 9, 'G##' : 9, 'Gx' : 9, 'Bb' : 9, 'Hbb' : 9, + 'B' : 10, 'A#' : 10, 'Hb' : 10, + 'H' : 11, 'B#' : 11, 'A##' : 11, 'Ax' : 11, 'Cb' : 11 + }, + 'english': { + 'C' : 0, 'B#' : 0, 'Dbb' : 0, + 'C#' : 1, 'Db' : 1, 'B##' : 1, 'Bx' : 1, + 'D' : 2, 'C##' : 2, 'Cx' : 2, 'Ebb' : 2, + 'D#' : 3, 'Eb' : 3, + 'E' : 4, 'D##' : 4, 'Dx' : 4, 'Fb' : 4, + 'F' : 5, 'E#' : 5, 'Gbb' : 5, + 'F#' : 6, 'Gb' : 6, + 'G' : 7, 'F##' : 7, 'Fx' : 7, 'Abb' : 7, + 'G#' : 8, 'Ab' : 8, + 'A' : 9, 'G##' : 9, 'Gx' : 9, 'Bbb' : 9, + 'Bb' : 10, 'A#' : 10, + 'B' : 11, 'A##' : 11, 'Ax' : 11, 'Cb' : 11 + } + } + chord = chord.replace('♭', 'b').replace('♯', '#') transposed_chord = '' - last_chord = '' + minor = '' + thischordchangeskey = False notes_sharp = notes_sharp_notation[notation] notes_flat = notes_flat_notation[notation] - notes_preferred = ['b', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#'] - for i in range(0, len(chord_split)): - if i > 0: - transposed_chord += '/' - current_chord = chord_split[i] - if current_chord and current_chord[0] == '(': - transposed_chord += '(' - if len(current_chord) > 1: - current_chord = current_chord[1:] + notes_preferred = ['b', '#', '#', 'b', '#', 'b', '#', '#', 'b', '#', 'b', '#'] + if chord and chord[0] == '(': + transposed_chord += '(' + if len(chord) > 1: + chord = chord[1:] + else: + chord = '' + if chord and chord[0] == '=': + transposed_chord += '=' + if len(chord) > 1: + chord = chord[1:] + thischordchangeskey = True + else: + chord = '' + if chord and chord[0] == '|': + transposed_chord += '|' + if len(chord) > 1: + chord = chord[1:] + else: + chord = '' + if len(chord) > 0: + if notation == 'neo-latin': + if len(chord) > 2 and chord[0:3].lower() == 'sol': + note = chord[0:3] + chord = chord[3:] if len(chord) > 3 else '' + elif len(chord) > 1: + note = chord[0:2] + chord = chord[2:] if len(chord) > 2 else '' + else: + note = chord[0] + chord = chord[1:] if len(chord) > 1 else '' + while len(chord) > 0 and '#bx'.find(chord[0]) > -1: + note += chord[0] + chord = chord[1:] if len(chord) > 0 else '' + if len(chord) > 0: + if 'm-'.find(chord[0]) > -1 or (len(chord) > 1 and chord[0:2].lower() == 'mi'): + minor = chord[0] + chord = chord[1:] if len(chord) > 1 else '' else: - current_chord = '' - if current_chord and current_chord[0] == '=': - transposed_chord += '=' - if len(current_chord) > 1: - current_chord = current_chord[1:] - else: - current_chord = '' - if current_chord and current_chord[0] == '|': - transposed_chord += '|' - if len(current_chord) > 1: - current_chord = current_chord[1:] - else: - current_chord = '' - if len(current_chord) > 0: - if len(current_chord) > 1: - if '#b'.find(current_chord[1]) == -1: - note = current_chord[0:1] - rest = current_chord[1:] - else: - note = current_chord[0:2] - rest = current_chord[2:] - else: - note = current_chord - rest = '' - note_number = notes_flat.index(note) if note not in notes_sharp else notes_sharp.index(note) + minor = '' + if note in notenumbers[notation]: + note_number = notenumbers[notation][note] note_number += transpose_value while note_number > 11: note_number -= 12 while note_number < 0: note_number += 12 - if i == 0: - current_chord = notes_sharp[note_number] if notes_preferred[note_number] == '#' else notes_flat[ - note_number] - last_chord = current_chord + if isbass: + if lastchord: + note = scales[notation][lastchord][note_number] + elif key: + note = scales[notation][key][note_number] + else: + note = notes_sharp[note_number] if notes_preferred[note_number] == '#' else notes_flat[note_number] else: - current_chord = notes_flat[note_number] if last_chord not in notes_sharp else notes_sharp[note_number] - if not (note not in notes_flat and note not in notes_sharp): - transposed_chord += current_chord + rest - else: - transposed_chord += note + rest - return transposed_chord + if not key or thischordchangeskey: + note = notes_sharp[note_number] if notes_preferred[note_number] == '#' else notes_flat[note_number] + else: + note = scales[notation][key][note_number] + transposed_chord += note + minor + chord + else: + transposed_chord += chord + if thischordchangeskey: + key = note + minor + else: + if not isbass: lastchord = note + minor + return transposed_chord, key, lastchord From 6ea2f9d43d3170effde485b4d88ac44ccdcef9e2 Mon Sep 17 00:00:00 2001 From: STEPHANVS Date: Thu, 22 Jul 2021 22:48:10 +0200 Subject: [PATCH 13/21] Pipeline fixes --- openlp/plugins/songs/lib/__init__.py | 202 +++++++++++++------------ tests/openlp_plugins/songs/test_lib.py | 12 +- 2 files changed, 108 insertions(+), 106 deletions(-) diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index 83d2354ca..6d990e101 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -603,7 +603,8 @@ def transpose_verse(verse_text, transpose_value, notation, key): transposed_lyrics += word else: # This MUST be a chord - transposed_chord, key, lastchord = transpose_chord(word, transpose_value, notation, key, lastchord, isbass) + transposed_chord, key, lastchord = transpose_chord(word, transpose_value, notation, key, lastchord, + isbass) isbass = False transposed_lyrics += transposed_chord # If still inside a chord tag something is wrong! @@ -636,112 +637,112 @@ def transpose_chord(chord, transpose_value, notation, key, lastchord, isbass): } scales = { 'german': { - 'C' : ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'B', 'H'], - 'Am' : ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'B', 'H'], - 'C#' : ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'H'], - 'A#m' : ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'H'], - 'Db' : ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bb', 'B', 'Cb'], - 'Bm' : ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bb', 'B', 'Cb'], - 'D' : ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'B', 'H'], - 'Hm' : ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'B', 'H'], - 'D#' : ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'H'], - 'H#m' : ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'H'], - 'Eb' : ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bb', 'B', 'Cb'], - 'Cm' : ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bb', 'B', 'Cb'], - 'E' : ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'B', 'H'], - 'C#m' : ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'B', 'H'], - 'F' : ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'B', 'Cb'], - 'Dm' : ['C', 'C#', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'B', 'H'], - 'F#' : ['C', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'H'], - 'D#m' : ['C', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'H'], - 'Gb' : ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bb', 'B', 'Cb'], - 'Ebm' : ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bb', 'B', 'Cb'], - 'G' : ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'B', 'H'], - 'Em' : ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'B', 'H'], - 'G#' : ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'H'], - 'E#m' : ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'H'], - 'Ab' : ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bb', 'B', 'Cb'], - 'Fm' : ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bb', 'B', 'Cb'], - 'A' : ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'G#', 'A', 'B', 'H'], - 'F#m' : ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'G#', 'A', 'B', 'H'], - 'A#' : ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'Gx', 'A#', 'H'], - 'F##m' : ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'Gx', 'A#', 'H'], - 'Fxm' : ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'Gx', 'A#', 'H'], - 'B' : ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'A', 'B', 'Cb'], - 'Gm' : ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'A', 'B', 'Cb'], - 'H' : ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'H'], - 'G#m' : ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'H'], - 'Cb' : ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'Gbb', 'Gb', 'Abb', 'Ab', 'Bb', 'B', 'Cb'], - 'Abm' : ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'Gbb', 'Gb', 'Abb', 'Ab', 'Bb', 'B', 'Cb'] + 'C': ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'B', 'H'], + 'Am': ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'B', 'H'], + 'C#': ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'H'], + 'A#m': ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'H'], + 'Db': ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bb', 'B', 'Cb'], + 'Bm': ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bb', 'B', 'Cb'], + 'D': ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'B', 'H'], + 'Hm': ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'B', 'H'], + 'D#': ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'H'], + 'H#m': ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'H'], + 'Eb': ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bb', 'B', 'Cb'], + 'Cm': ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bb', 'B', 'Cb'], + 'E': ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'B', 'H'], + 'C#m': ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'B', 'H'], + 'F': ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'B', 'Cb'], + 'Dm': ['C', 'C#', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'B', 'H'], + 'F#': ['C', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'H'], + 'D#m': ['C', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'H'], + 'Gb': ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bb', 'B', 'Cb'], + 'Ebm': ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bb', 'B', 'Cb'], + 'G': ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'B', 'H'], + 'Em': ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'B', 'H'], + 'G#': ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'H'], + 'E#m': ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'H'], + 'Ab': ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bb', 'B', 'Cb'], + 'Fm': ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bb', 'B', 'Cb'], + 'A': ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'G#', 'A', 'B', 'H'], + 'F#m': ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'G#', 'A', 'B', 'H'], + 'A#': ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'Gx', 'A#', 'H'], + 'F##m': ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'Gx', 'A#', 'H'], + 'Fxm': ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'Gx', 'A#', 'H'], + 'B': ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'A', 'B', 'Cb'], + 'Gm': ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'A', 'B', 'Cb'], + 'H': ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'H'], + 'G#m': ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'H'], + 'Cb': ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'Gbb', 'Gb', 'Abb', 'Ab', 'Bb', 'B', 'Cb'], + 'Abm': ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'Gbb', 'Gb', 'Abb', 'Ab', 'Bb', 'B', 'Cb'] }, 'english': { - 'C' : ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], - 'Am' : ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], - 'C#' : ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'B'], - 'A#m' : ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'B'], - 'Db' : ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'], - 'Bm' : ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'], - 'D' : ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], - 'Hm' : ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], - 'D#' : ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'B'], - 'H#m' : ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'B'], - 'Eb' : ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bbb', 'Bb', 'Cb'], - 'Cm' : ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bbb', 'Bb', 'Cb'], - 'E' : ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'Bb', 'B'], - 'C#m' : ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'Bb', 'B'], - 'F' : ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'Cb'], - 'Dm' : ['C', 'C#', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B'], - 'F#' : ['C', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'B'], - 'D#m' : ['C', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'B'], - 'Gb' : ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'], - 'Ebm' : ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'], - 'G' : ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], - 'Em' : ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], - 'G#' : ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'B'], - 'E#m' : ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'B'], - 'Ab' : ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bbb', 'Bb', 'Cb'], - 'Fm' : ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bbb', 'Bb', 'Cb'], - 'A' : ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'G#', 'A', 'Bb', 'B'], - 'F#m' : ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'G#', 'A', 'Bb', 'B'], - 'A#' : ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'Gx', 'A#', 'B'], - 'F##m' : ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'Gx', 'A#', 'B'], - 'Fxm' : ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'Gx', 'A#', 'B'], - 'B' : ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'Cb'], - 'Gm' : ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'Cb'], - 'H' : ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'], - 'G#m' : ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'], - 'Cb' : ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'Gbb', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'], - 'Abm' : ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'Gbb', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'] + 'C': ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], + 'Am': ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], + 'C#': ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'B'], + 'A#m': ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'B'], + 'Db': ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'], + 'Bm': ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'], + 'D': ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], + 'Hm': ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], + 'D#': ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'B'], + 'H#m': ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'B'], + 'Eb': ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bbb', 'Bb', 'Cb'], + 'Cm': ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bbb', 'Bb', 'Cb'], + 'E': ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'Bb', 'B'], + 'C#m': ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'Bb', 'B'], + 'F': ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'Cb'], + 'Dm': ['C', 'C#', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B'], + 'F#': ['C', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'B'], + 'D#m': ['C', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'B'], + 'Gb': ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'], + 'Ebm': ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'], + 'G': ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], + 'Em': ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], + 'G#': ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'B'], + 'E#m': ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'B'], + 'Ab': ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bbb', 'Bb', 'Cb'], + 'Fm': ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bbb', 'Bb', 'Cb'], + 'A': ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'G#', 'A', 'Bb', 'B'], + 'F#m': ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'G#', 'A', 'Bb', 'B'], + 'A#': ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'Gx', 'A#', 'B'], + 'F##m': ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'Gx', 'A#', 'B'], + 'Fxm': ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'Gx', 'A#', 'B'], + 'B': ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'Cb'], + 'Gm': ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'Cb'], + 'H': ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'], + 'G#m': ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'], + 'Cb': ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'Gbb', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'], + 'Abm': ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'Gbb', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'] } } notenumbers = { 'german': { - 'C' : 0, 'H#' : 0, 'B##' : 0, 'Bx' : 0, 'Dbb' : 0, - 'C#' : 1, 'Db' : 1, - 'D' : 2, 'C##' : 2, 'Cx' : 2, 'Ebb' : 2, - 'D#' : 3, 'Eb' : 3, - 'E' : 4, 'D##' : 4, 'Dx' : 4, 'Fb' : 4, - 'F' : 5, 'E#' : 5, 'Gbb' : 5, - 'F#' : 6, 'Gb' : 6, - 'G' : 7, 'F##' : 7, 'Fx' : 7, 'Abb' : 7, - 'G#' : 8, 'Ab' : 8, - 'A' : 9, 'G##' : 9, 'Gx' : 9, 'Bb' : 9, 'Hbb' : 9, - 'B' : 10, 'A#' : 10, 'Hb' : 10, - 'H' : 11, 'B#' : 11, 'A##' : 11, 'Ax' : 11, 'Cb' : 11 + 'C': 0, 'H#': 0, 'B##': 0, 'Bx': 0, 'Dbb': 0, + 'C#': 1, 'Db': 1, + 'D': 2, 'C##': 2, 'Cx': 2, 'Ebb': 2, + 'D#': 3, 'Eb': 3, + 'E': 4, 'D##': 4, 'Dx': 4, 'Fb': 4, + 'F': 5, 'E#': 5, 'Gbb': 5, + 'F#': 6, 'Gb': 6, + 'G': 7, 'F##': 7, 'Fx': 7, 'Abb': 7, + 'G#': 8, 'Ab': 8, + 'A': 9, 'G##': 9, 'Gx': 9, 'Bb': 9, 'Hbb': 9, + 'B': 10, 'A#': 10, 'Hb': 10, + 'H': 11, 'B#': 11, 'A##': 11, 'Ax': 11, 'Cb': 11 }, 'english': { - 'C' : 0, 'B#' : 0, 'Dbb' : 0, - 'C#' : 1, 'Db' : 1, 'B##' : 1, 'Bx' : 1, - 'D' : 2, 'C##' : 2, 'Cx' : 2, 'Ebb' : 2, - 'D#' : 3, 'Eb' : 3, - 'E' : 4, 'D##' : 4, 'Dx' : 4, 'Fb' : 4, - 'F' : 5, 'E#' : 5, 'Gbb' : 5, - 'F#' : 6, 'Gb' : 6, - 'G' : 7, 'F##' : 7, 'Fx' : 7, 'Abb' : 7, - 'G#' : 8, 'Ab' : 8, - 'A' : 9, 'G##' : 9, 'Gx' : 9, 'Bbb' : 9, - 'Bb' : 10, 'A#' : 10, - 'B' : 11, 'A##' : 11, 'Ax' : 11, 'Cb' : 11 + 'C': 0, 'B#': 0, 'Dbb': 0, + 'C#': 1, 'Db': 1, 'B##': 1, 'Bx': 1, + 'D': 2, 'C##': 2, 'Cx': 2, 'Ebb': 2, + 'D#': 3, 'Eb': 3, + 'E': 4, 'D##': 4, 'Dx': 4, 'Fb': 4, + 'F': 5, 'E#': 5, 'Gbb': 5, + 'F#': 6, 'Gb': 6, + 'G': 7, 'F##': 7, 'Fx': 7, 'Abb': 7, + 'G#': 8, 'Ab': 8, + 'A': 9, 'G##': 9, 'Gx': 9, 'Bbb': 9, + 'Bb': 10, 'A#': 10, + 'B': 11, 'A##': 11, 'Ax': 11, 'Cb': 11 } } chord = chord.replace('♭', 'b').replace('♯', '#') @@ -815,5 +816,6 @@ def transpose_chord(chord, transpose_value, notation, key, lastchord, isbass): if thischordchangeskey: key = note + minor else: - if not isbass: lastchord = note + minor + if not isbass: + lastchord = note + minor return transposed_chord, key, lastchord diff --git a/tests/openlp_plugins/songs/test_lib.py b/tests/openlp_plugins/songs/test_lib.py index ea08e1b0e..3a36b9555 100644 --- a/tests/openlp_plugins/songs/test_lib.py +++ b/tests/openlp_plugins/songs/test_lib.py @@ -277,7 +277,7 @@ def test_transpose_chord_up(): chord = 'C' # WHEN: Transposing it 1 up - new_chord = transpose_chord(chord, 1, 'english') + new_chord = transpose_chord(chord, 1, 'english', None, None, False) # THEN: The chord should be transposed up one note assert new_chord == 'C#', 'The chord should be transposed up.' @@ -288,13 +288,13 @@ def test_transpose_chord_up_adv(): Test that the transpose_chord() method works when transposing up an advanced chord """ # GIVEN: An advanced Chord - chord = '(C/D#)' + chord = '(D/F#)' # WHEN: Transposing it 1 up - new_chord = transpose_chord(chord, 1, 'english') + new_chord = transpose_chord(chord, 1, 'english', None, None, False) # THEN: The chord should be transposed up one note - assert new_chord == '(C#/E)', 'The chord should be transposed up.' + assert new_chord == '(Eb/G)', 'The chord should be transposed up.' def test_transpose_chord_down(): @@ -305,7 +305,7 @@ def test_transpose_chord_down(): chord = 'C' # WHEN: Transposing it 1 down - new_chord = transpose_chord(chord, -1, 'english') + new_chord = transpose_chord(chord, -1, 'english', None, None, False) # THEN: The chord should be transposed down one note assert new_chord == 'B', 'The chord should be transposed down.' @@ -321,7 +321,7 @@ def test_transpose_chord_error(): # WHEN: Transposing it 1 down # THEN: An exception should be raised with pytest.raises(ValueError) as err: - transpose_chord(chord, -1, 'english') + transpose_chord(chord, -1, 'english', None, None, False) assert err.value != ValueError('\'T\' is not in list'), \ 'ValueError exception should have been thrown for invalid chord' From d0d9653c67d999cdda105588add5d1ee3561d338 Mon Sep 17 00:00:00 2001 From: STEPHANVS Date: Thu, 22 Jul 2021 23:08:23 +0200 Subject: [PATCH 14/21] More pipeline fixes --- openlp/plugins/songs/lib/__init__.py | 2 +- tests/openlp_plugins/songs/test_lib.py | 31 +++++++++++++++++++++----- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index 6d990e101..b69d38ae0 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -604,7 +604,7 @@ def transpose_verse(verse_text, transpose_value, notation, key): else: # This MUST be a chord transposed_chord, key, lastchord = transpose_chord(word, transpose_value, notation, key, lastchord, - isbass) + isbass) isbass = False transposed_lyrics += transposed_chord # If still inside a chord tag something is wrong! diff --git a/tests/openlp_plugins/songs/test_lib.py b/tests/openlp_plugins/songs/test_lib.py index 3a36b9555..56dfc9f5b 100644 --- a/tests/openlp_plugins/songs/test_lib.py +++ b/tests/openlp_plugins/songs/test_lib.py @@ -275,12 +275,17 @@ def test_transpose_chord_up(): """ # GIVEN: A Chord chord = 'C' + key = None + lastchord = None + isbass = False # WHEN: Transposing it 1 up - new_chord = transpose_chord(chord, 1, 'english', None, None, False) + new_chord, key, lastchord = transpose_chord(chord, 1, 'english', key, lastchord, isbass) # THEN: The chord should be transposed up one note assert new_chord == 'C#', 'The chord should be transposed up.' + assert key == None, 'The key should not be set' + assert lastchord == 'C#', 'If not isbass, then lastchord should be returned' def test_transpose_chord_up_adv(): @@ -289,13 +294,22 @@ def test_transpose_chord_up_adv(): """ # GIVEN: An advanced Chord chord = '(D/F#)' - + key = None + lastchord = None + isbass = False + chordsplit = chord.split("/") # WHEN: Transposing it 1 up - new_chord = transpose_chord(chord, 1, 'english', None, None, False) + new_chord, key, lastchord = transpose_chord(chordsplit[0], 1, 'english', key, lastchord, isbass) + + # AFTER "/" isbass is true, lastchord is set + isbass = True + new_bass, key, lastchord = transpose_chord(chordsplit[1], 1, 'english', key, lastchord, isbass) # THEN: The chord should be transposed up one note - assert new_chord == '(Eb/G)', 'The chord should be transposed up.' - + assert new_chord == '(Eb', 'The chord should be transposed up.' + assert new_bass == 'G)', 'Bass should be transposed up.' + assert key == None, 'no key should be defined' + assert lastchord == 'Eb', 'lastchord is generated' def test_transpose_chord_down(): """ @@ -303,12 +317,17 @@ def test_transpose_chord_down(): """ # GIVEN: A Chord chord = 'C' + key = None + lastchord = None + isbass = False # WHEN: Transposing it 1 down - new_chord = transpose_chord(chord, -1, 'english', None, None, False) + new_chord, key, lastchord = transpose_chord(chord, -1, 'english', key, lastchord, isbass) # THEN: The chord should be transposed down one note assert new_chord == 'B', 'The chord should be transposed down.' + assert key == None, 'The key should not be set' + assert lastchord == 'B', 'If not isbass, then lastchord should be returned' def test_transpose_chord_error(): From a5e3fef2fa5be0ef942cc23ba6bfe8151b753e9f Mon Sep 17 00:00:00 2001 From: STEPHANVS Date: Thu, 22 Jul 2021 23:34:16 +0200 Subject: [PATCH 15/21] Even more pipeline fixes --- openlp/plugins/songs/lib/__init__.py | 2 +- tests/openlp_plugins/songs/test_lib.py | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index b69d38ae0..b7c00afe1 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -812,7 +812,7 @@ def transpose_chord(chord, transpose_value, notation, key, lastchord, isbass): note = scales[notation][key][note_number] transposed_chord += note + minor + chord else: - transposed_chord += chord + transposed_chord += note + chord if thischordchangeskey: key = note + minor else: diff --git a/tests/openlp_plugins/songs/test_lib.py b/tests/openlp_plugins/songs/test_lib.py index 56dfc9f5b..ee4cc5c54 100644 --- a/tests/openlp_plugins/songs/test_lib.py +++ b/tests/openlp_plugins/songs/test_lib.py @@ -284,7 +284,7 @@ def test_transpose_chord_up(): # THEN: The chord should be transposed up one note assert new_chord == 'C#', 'The chord should be transposed up.' - assert key == None, 'The key should not be set' + assert key is None, 'The key should not be set' assert lastchord == 'C#', 'If not isbass, then lastchord should be returned' @@ -308,7 +308,7 @@ def test_transpose_chord_up_adv(): # THEN: The chord should be transposed up one note assert new_chord == '(Eb', 'The chord should be transposed up.' assert new_bass == 'G)', 'Bass should be transposed up.' - assert key == None, 'no key should be defined' + assert key is None, 'no key should be defined' assert lastchord == 'Eb', 'lastchord is generated' def test_transpose_chord_down(): @@ -326,7 +326,7 @@ def test_transpose_chord_down(): # THEN: The chord should be transposed down one note assert new_chord == 'B', 'The chord should be transposed down.' - assert key == None, 'The key should not be set' + assert key is None, 'The key should not be set' assert lastchord == 'B', 'If not isbass, then lastchord should be returned' @@ -363,10 +363,10 @@ def test_transpose_lyrics(mocked_transpose_verse, mock_settings): transpose_lyrics(lyrics, 1) # THEN: transpose_verse should have been called - mocked_transpose_verse.assert_any_call('', 1, 'english') - mocked_transpose_verse.assert_any_call('\nAmazing grace how sweet the sound\n', 1, 'english') - mocked_transpose_verse.assert_any_call('\nThat saved a wretch like me.\n', 1, 'english') - mocked_transpose_verse.assert_any_call('\nI once was lost but now I\'m found.', 1, 'english') + mocked_transpose_verse.assert_any_call('', 1, 'english', None) + mocked_transpose_verse.assert_any_call('\nAmazing grace how sweet the sound\n', 1, 'english', None) + mocked_transpose_verse.assert_any_call('\nThat saved a wretch like me.\n', 1, 'english', None) + mocked_transpose_verse.assert_any_call('\nI once was lost but now I\'m found.', 1, 'english', None) def test_translated_tag(): From 0ae79b8c586519a21b4bb44a21712aafbb4a7993 Mon Sep 17 00:00:00 2001 From: STEPHANVS Date: Fri, 23 Jul 2021 00:14:53 +0200 Subject: [PATCH 16/21] Invalid chord throws KeyError, not ValueError --- openlp/plugins/songs/forms/editverseform.py | 12 +++---- openlp/plugins/songs/lib/__init__.py | 40 ++++++++++----------- tests/openlp_plugins/songs/test_lib.py | 6 ++-- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/openlp/plugins/songs/forms/editverseform.py b/openlp/plugins/songs/forms/editverseform.py index 710ae3785..044d9df7b 100644 --- a/openlp/plugins/songs/forms/editverseform.py +++ b/openlp/plugins/songs/forms/editverseform.py @@ -124,12 +124,12 @@ class EditVerseForm(QtWidgets.QDialog, Ui_EditVerseDialog): try: transposed_lyrics = transpose_lyrics(self.verse_text_edit.toPlainText(), 1) self.verse_text_edit.setPlainText(transposed_lyrics) - except ValueError as ve: + except KeyError as ke: # Transposing failed critical_error_message_box(title=translate('SongsPlugin.EditVerseForm', 'Transposing failed'), message=translate('SongsPlugin.EditVerseForm', 'Transposing failed because of invalid chord:\n{err_msg}' - .format(err_msg=ve))) + .format(err_msg=ke))) return self.verse_text_edit.setFocus() self.verse_text_edit.moveCursor(QtGui.QTextCursor.End) @@ -141,12 +141,12 @@ class EditVerseForm(QtWidgets.QDialog, Ui_EditVerseDialog): try: transposed_lyrics = transpose_lyrics(self.verse_text_edit.toPlainText(), -1) self.verse_text_edit.setPlainText(transposed_lyrics) - except ValueError as ve: + except KeyError as ke: # Transposing failed critical_error_message_box(title=translate('SongsPlugin.EditVerseForm', 'Transposing failed'), message=translate('SongsPlugin.EditVerseForm', 'Transposing failed because of invalid chord:\n{err_msg}' - .format(err_msg=ve))) + .format(err_msg=ke))) return self.verse_text_edit.setPlainText(transposed_lyrics) self.verse_text_edit.setFocus() @@ -235,11 +235,11 @@ class EditVerseForm(QtWidgets.QDialog, Ui_EditVerseDialog): try: transpose_lyrics(self.verse_text_edit.toPlainText(), 0) super(EditVerseForm, self).accept() - except ValueError as ve: + except KeyError as ke: # Transposing failed critical_error_message_box(title=translate('SongsPlugin.EditVerseForm', 'Invalid Chord'), message=translate('SongsPlugin.EditVerseForm', 'An invalid chord was detected:\n{err_msg}' - .format(err_msg=ve))) + .format(err_msg=ke))) else: super(EditVerseForm, self).accept() diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index b7c00afe1..19cc8d8cf 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -791,28 +791,28 @@ def transpose_chord(chord, transpose_value, notation, key, lastchord, isbass): chord = chord[1:] if len(chord) > 1 else '' else: minor = '' - if note in notenumbers[notation]: - note_number = notenumbers[notation][note] - note_number += transpose_value - while note_number > 11: - note_number -= 12 - while note_number < 0: - note_number += 12 - if isbass: - if lastchord: - note = scales[notation][lastchord][note_number] - elif key: - note = scales[notation][key][note_number] - else: - note = notes_sharp[note_number] if notes_preferred[note_number] == '#' else notes_flat[note_number] + #if note in notenumbers[notation]: + note_number = notenumbers[notation][note] + note_number += transpose_value + while note_number > 11: + note_number -= 12 + while note_number < 0: + note_number += 12 + if isbass: + if lastchord: + note = scales[notation][lastchord][note_number] + elif key: + note = scales[notation][key][note_number] else: - if not key or thischordchangeskey: - note = notes_sharp[note_number] if notes_preferred[note_number] == '#' else notes_flat[note_number] - else: - note = scales[notation][key][note_number] - transposed_chord += note + minor + chord + note = notes_sharp[note_number] if notes_preferred[note_number] == '#' else notes_flat[note_number] else: - transposed_chord += note + chord + if not key or thischordchangeskey: + note = notes_sharp[note_number] if notes_preferred[note_number] == '#' else notes_flat[note_number] + else: + note = scales[notation][key][note_number] + transposed_chord += note + minor + chord + #else: + # transposed_chord += note + chord if thischordchangeskey: key = note + minor else: diff --git a/tests/openlp_plugins/songs/test_lib.py b/tests/openlp_plugins/songs/test_lib.py index ee4cc5c54..ca64f8d68 100644 --- a/tests/openlp_plugins/songs/test_lib.py +++ b/tests/openlp_plugins/songs/test_lib.py @@ -339,10 +339,10 @@ def test_transpose_chord_error(): # WHEN: Transposing it 1 down # THEN: An exception should be raised - with pytest.raises(ValueError) as err: + with pytest.raises(KeyError) as err: transpose_chord(chord, -1, 'english', None, None, False) - assert err.value != ValueError('\'T\' is not in list'), \ - 'ValueError exception should have been thrown for invalid chord' + assert err.value != KeyError('\'T\' is not in list'), \ + 'KeyError exception should have been thrown for invalid chord' @patch('openlp.plugins.songs.lib.transpose_verse') From 0efb61f8f723632ea937867c83614e0348dd2406 Mon Sep 17 00:00:00 2001 From: STEPHANVS Date: Fri, 23 Jul 2021 00:44:29 +0200 Subject: [PATCH 17/21] Notation fixes --- openlp/plugins/songs/lib/__init__.py | 86 ++++++++++++++++++++------ tests/openlp_plugins/songs/test_lib.py | 1 + 2 files changed, 69 insertions(+), 18 deletions(-) diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index 19cc8d8cf..4f657476d 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -678,14 +678,14 @@ def transpose_chord(chord, transpose_value, notation, key, lastchord, isbass): 'english': { 'C': ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], 'Am': ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], - 'C#': ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'B'], - 'A#m': ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'B'], + 'C#': ['B#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'B'], + 'A#m': ['B#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'B'], 'Db': ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'], 'Bm': ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'], 'D': ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], - 'Hm': ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], - 'D#': ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'B'], - 'H#m': ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'B'], + 'Bm': ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], + 'D#': ['B#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'B'], + 'B#m': ['B#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'B'], 'Eb': ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bbb', 'Bb', 'Cb'], 'Cm': ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bbb', 'Bb', 'Cb'], 'E': ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'Bb', 'B'], @@ -698,21 +698,60 @@ def transpose_chord(chord, transpose_value, notation, key, lastchord, isbass): 'Ebm': ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'], 'G': ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], 'Em': ['C', 'Db', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], - 'G#': ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'B'], - 'E#m': ['H#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'B'], + 'G#': ['B#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'B'], + 'E#m': ['B#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'B'], 'Ab': ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bbb', 'Bb', 'Cb'], 'Fm': ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'Bbb', 'Bb', 'Cb'], 'A': ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'G#', 'A', 'Bb', 'B'], 'F#m': ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'G#', 'A', 'Bb', 'B'], - 'A#': ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'Gx', 'A#', 'B'], - 'F##m': ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'Gx', 'A#', 'B'], - 'Fxm': ['H#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'Gx', 'A#', 'B'], - 'B': ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'Cb'], + 'A#': ['B#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'Gx', 'A#', 'B'], + 'F##m': ['B#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'Gx', 'A#', 'B'], + 'Fxm': ['B#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'Gx', 'A#', 'B'], + 'Bb': ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'Cb'], 'Gm': ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'Cb'], - 'H': ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'], + 'B': ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'], 'G#m': ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'], 'Cb': ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'Gbb', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'], 'Abm': ['Dbb', 'Db', 'Ebb', 'Eb', 'Fb', 'Gbb', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'] + }, + 'neo-latin': { + 'Do': ['Do', 'Reb', 'Re', 'Mib', 'Mi', 'Fa', 'Fa#', 'Sol', 'Lab', 'La', 'Sib', 'Si'], + 'Lam': ['Do', 'Reb', 'Re', 'Mib', 'Mi', 'Fa', 'Fa#', 'Sol', 'Lab', 'La', 'Sib', 'Si'], + 'Do#': ['Si#', 'Do#', 'Re', 'Re#', 'Mi', 'Mi#', 'Fa#', 'Sol', 'Sol#', 'La', 'La#', 'Si'], + 'La#m': ['Si#', 'Do#', 'Re', 'Re#', 'Mi', 'Mi#', 'Fa#', 'Sol', 'Sol#', 'La', 'La#', 'Si'], + 'Reb': ['Do', 'Reb', 'Mibb', 'Mib', 'Fab', 'Fa', 'Solb', 'Labb', 'Lab', 'Sibb', 'Sib', 'Dob'], + 'Sim': ['Do', 'Reb', 'Mibb', 'Mib', 'Fab', 'Fa', 'Solb', 'Labb', 'Lab', 'Sibb', 'Sib', 'Dob'], + 'Re': ['Do', 'Do#', 'Re', 'Mib', 'Mi', 'Fa', 'Fa#', 'Sol', 'Lab', 'La', 'Sib', 'Si'], + 'Sim': ['Do', 'Do#', 'Re', 'Mib', 'Mi', 'Fa', 'Fa#', 'Sol', 'Lab', 'La', 'Sib', 'Si'], + 'Re#': ['Si#', 'Do#', 'Dox', 'Re#', 'Mi', 'Mi#', 'Fa#', 'Fax', 'Sol#', 'La', 'La#', 'Si'], + 'Si#m': ['Si#', 'Do#', 'Dox', 'Re#', 'Mi', 'Mi#', 'Fa#', 'Fax', 'Sol#', 'La', 'La#', 'Si'], + 'Mib': ['Do', 'Reb', 'Re', 'Mib', 'Fab', 'Fa', 'Solb', 'Sol', 'Lab', 'Sibb', 'Sib', 'Dob'], + 'Dom': ['Do', 'Reb', 'Re', 'Mib', 'Fab', 'Fa', 'Solb', 'Sol', 'Lab', 'Sibb', 'Sib', 'Dob'], + 'Mi': ['Do', 'Do#', 'Re', 'Re#', 'Mi', 'Fa', 'Fa#', 'Sol', 'Sol#', 'La', 'Sib', 'Si'], + 'Do#m': ['Do', 'Do#', 'Re', 'Re#', 'Mi', 'Fa', 'Fa#', 'Sol', 'Sol#', 'La', 'Sib', 'Si'], + 'Fa': ['Do', 'Reb', 'Re', 'Mib', 'Mi', 'Fa', 'Solb', 'Sol', 'Lab', 'La', 'Sib', 'Dob'], + 'Rem': ['Do', 'Do#', 'Re', 'Mib', 'Mi', 'Fa', 'Solb', 'Sol', 'Lab', 'La', 'Sib', 'Si'], + 'Fa#': ['Do', 'Do#', 'Re', 'Re#', 'Mi', 'Mi#', 'Fa#', 'Sol', 'Sol#', 'La', 'La#', 'Si'], + 'Re#m': ['Do', 'Do#', 'Re', 'Re#', 'Mi', 'Mi#', 'Fa#', 'Sol', 'Sol#', 'La', 'La#', 'Si'], + 'Solb': ['Rebb', 'Reb', 'Mibb', 'Mib', 'Fab', 'Fa', 'Solb', 'Labb', 'Lab', 'Sibb', 'Sib', 'Dob'], + 'Mibm': ['Rebb', 'Reb', 'Mibb', 'Mib', 'Fab', 'Fa', 'Solb', 'Labb', 'Lab', 'Sibb', 'Sib', 'Dob'], + 'Sol': ['Do', 'Reb', 'Re', 'Mib', 'Mi', 'Fa', 'Fa#', 'Sol', 'Lab', 'La', 'Sib', 'Si'], + 'Mim': ['Do', 'Reb', 'Re', 'Mib', 'Mi', 'Fa', 'Fa#', 'Sol', 'Lab', 'La', 'Sib', 'Si'], + 'Sol#': ['Si#', 'Do#', 'Re', 'Re#', 'Mi', 'Mi#', 'Fa#', 'Fax', 'Sol#', 'La', 'La#', 'Si'], + 'Mi#m': ['Si#', 'Do#', 'Re', 'Re#', 'Mi', 'Mi#', 'Fa#', 'Fax', 'Sol#', 'La', 'La#', 'Si'], + 'Lab': ['Do', 'Reb', 'Mibb', 'Mib', 'Fab', 'Fa', 'Solb', 'Sol', 'Lab', 'Sibb', 'Sib', 'Dob'], + 'Fam': ['Do', 'Reb', 'Mibb', 'Mib', 'Fab', 'Fa', 'Solb', 'Sol', 'Lab', 'Sibb', 'Sib', 'Dob'], + 'La': ['Do', 'Do#', 'Re', 'Mib', 'Mi', 'Fa', 'Fa#', 'Sol', 'Sol#', 'La', 'Sib', 'Si'], + 'Fa#m': ['Do', 'Do#', 'Re', 'Mib', 'Mi', 'Fa', 'Fa#', 'Sol', 'Sol#', 'La', 'Sib', 'Si'], + 'La#': ['Si#', 'Do#', 'Dox', 'Re#', 'Mi', 'Mi#', 'Fa#', 'Fax', 'Sol#', 'Solx', 'La#', 'Si'], + 'Fa##m': ['Si#', 'Do#', 'Dox', 'Re#', 'Mi', 'Mi#', 'Fa#', 'Fax', 'Sol#', 'Solx', 'La#', 'Si'], + 'Faxm': ['Si#', 'Do#', 'Dox', 'Re#', 'Mi', 'Mi#', 'Fa#', 'Fax', 'Sol#', 'Solx', 'La#', 'Si'], + 'Sib': ['Do', 'Reb', 'Re', 'Mib', 'Fab', 'Fa', 'Solb', 'Sol', 'Lab', 'La', 'Sib', 'Dob'], + 'Solm': ['Do', 'Reb', 'Re', 'Mib', 'Fab', 'Fa', 'Solb', 'Sol', 'Lab', 'La', 'Sib', 'Dob'], + 'Si': ['Do', 'Do#', 'Re', 'Re#', 'Mi', 'Fa', 'Fa#', 'Sol', 'Sol#', 'La', 'La#', 'Si'], + 'Sol#m': ['Do', 'Do#', 'Re', 'Re#', 'Mi', 'Fa', 'Fa#', 'Sol', 'Sol#', 'La', 'La#', 'Si'], + 'Dob': ['Rebb', 'Reb', 'Mibb', 'Mib', 'Fab', 'Solbb', 'Solb', 'Labb', 'Lab', 'Sibb', 'Sib', 'Dob'], + 'Labm': ['Rebb', 'Reb', 'Mibb', 'Mib', 'Fab', 'Solbb', 'Solb', 'Labb', 'Lab', 'Sibb', 'Sib', 'Dob'] } } notenumbers = { @@ -734,15 +773,29 @@ def transpose_chord(chord, transpose_value, notation, key, lastchord, isbass): 'C': 0, 'B#': 0, 'Dbb': 0, 'C#': 1, 'Db': 1, 'B##': 1, 'Bx': 1, 'D': 2, 'C##': 2, 'Cx': 2, 'Ebb': 2, - 'D#': 3, 'Eb': 3, + 'D#': 3, 'Eb': 3, 'Fbb': 3, 'E': 4, 'D##': 4, 'Dx': 4, 'Fb': 4, 'F': 5, 'E#': 5, 'Gbb': 5, - 'F#': 6, 'Gb': 6, + 'F#': 6, 'Gb': 6, 'E##': 6, 'Ex': 6, 'G': 7, 'F##': 7, 'Fx': 7, 'Abb': 7, 'G#': 8, 'Ab': 8, 'A': 9, 'G##': 9, 'Gx': 9, 'Bbb': 9, - 'Bb': 10, 'A#': 10, + 'Bb': 10, 'A#': 10, 'Cbb': 10, 'B': 11, 'A##': 11, 'Ax': 11, 'Cb': 11 + }, + 'neo-latin': { + 'Do': 0, 'Si#': 0, 'Rebb': 0, + 'Do#': 1, 'Reb': 1, 'Si##': 1, 'Six': 1, + 'Re': 2, 'Do##': 2, 'Dox': 2, 'Mibb': 2, + 'Re#': 3, 'Mib': 3, 'Fabb': 3, + 'Mi': 4, 'Re##': 4, 'Rex': 4, 'Fab': 4, + 'Fa': 5, 'Mi#': 5, 'Solbb': 5, + 'Fa#': 6, 'Solb': 6, 'Mi##': 6, 'Mix': 6, + 'Sol': 7, 'Fa##': 7, 'Fax': 7, 'Labb': 7, + 'Sol#': 8, 'Lab': 8, + 'La': 9, 'Sol##': 9, 'Solx': 9, 'Sibb': 9, + 'Sib': 10, 'La#': 10, 'Dobb': 10, + 'Si': 11, 'La##': 11, 'Lax': 11, 'Dob': 11 } } chord = chord.replace('♭', 'b').replace('♯', '#') @@ -791,7 +844,6 @@ def transpose_chord(chord, transpose_value, notation, key, lastchord, isbass): chord = chord[1:] if len(chord) > 1 else '' else: minor = '' - #if note in notenumbers[notation]: note_number = notenumbers[notation][note] note_number += transpose_value while note_number > 11: @@ -811,8 +863,6 @@ def transpose_chord(chord, transpose_value, notation, key, lastchord, isbass): else: note = scales[notation][key][note_number] transposed_chord += note + minor + chord - #else: - # transposed_chord += note + chord if thischordchangeskey: key = note + minor else: diff --git a/tests/openlp_plugins/songs/test_lib.py b/tests/openlp_plugins/songs/test_lib.py index ca64f8d68..1116fbcc0 100644 --- a/tests/openlp_plugins/songs/test_lib.py +++ b/tests/openlp_plugins/songs/test_lib.py @@ -311,6 +311,7 @@ def test_transpose_chord_up_adv(): assert key is None, 'no key should be defined' assert lastchord == 'Eb', 'lastchord is generated' + def test_transpose_chord_down(): """ Test that the transpose_chord() method works when transposing down From d329e2be79d1e78a02d758701418db75c7e45524 Mon Sep 17 00:00:00 2001 From: STEPHANVS Date: Fri, 23 Jul 2021 00:52:26 +0200 Subject: [PATCH 18/21] Notation fixes --- openlp/plugins/songs/lib/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index 4f657476d..0376dfeb0 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -681,7 +681,7 @@ def transpose_chord(chord, transpose_value, notation, key, lastchord, isbass): 'C#': ['B#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'B'], 'A#m': ['B#', 'C#', 'D', 'D#', 'E', 'E#', 'F#', 'G', 'G#', 'A', 'A#', 'B'], 'Db': ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'], - 'Bm': ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'], + 'Bbm': ['C', 'Db', 'Ebb', 'Eb', 'Fb', 'F', 'Gb', 'Abb', 'Ab', 'Bbb', 'Bb', 'Cb'], 'D': ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], 'Bm': ['C', 'C#', 'D', 'Eb', 'E', 'F', 'F#', 'G', 'Ab', 'A', 'Bb', 'B'], 'D#': ['B#', 'C#', 'Cx', 'D#', 'E', 'E#', 'F#', 'Fx', 'G#', 'A', 'A#', 'B'], @@ -720,7 +720,7 @@ def transpose_chord(chord, transpose_value, notation, key, lastchord, isbass): 'Do#': ['Si#', 'Do#', 'Re', 'Re#', 'Mi', 'Mi#', 'Fa#', 'Sol', 'Sol#', 'La', 'La#', 'Si'], 'La#m': ['Si#', 'Do#', 'Re', 'Re#', 'Mi', 'Mi#', 'Fa#', 'Sol', 'Sol#', 'La', 'La#', 'Si'], 'Reb': ['Do', 'Reb', 'Mibb', 'Mib', 'Fab', 'Fa', 'Solb', 'Labb', 'Lab', 'Sibb', 'Sib', 'Dob'], - 'Sim': ['Do', 'Reb', 'Mibb', 'Mib', 'Fab', 'Fa', 'Solb', 'Labb', 'Lab', 'Sibb', 'Sib', 'Dob'], + 'Sibm': ['Do', 'Reb', 'Mibb', 'Mib', 'Fab', 'Fa', 'Solb', 'Labb', 'Lab', 'Sibb', 'Sib', 'Dob'], 'Re': ['Do', 'Do#', 'Re', 'Mib', 'Mi', 'Fa', 'Fa#', 'Sol', 'Lab', 'La', 'Sib', 'Si'], 'Sim': ['Do', 'Do#', 'Re', 'Mib', 'Mi', 'Fa', 'Fa#', 'Sol', 'Lab', 'La', 'Sib', 'Si'], 'Re#': ['Si#', 'Do#', 'Dox', 'Re#', 'Mi', 'Mi#', 'Fa#', 'Fax', 'Sol#', 'La', 'La#', 'Si'], From 93f17c365cb2d1354fe6a8fbeca86099e1a3da90 Mon Sep 17 00:00:00 2001 From: STEPHANVS Date: Sat, 24 Jul 2021 13:17:05 +0200 Subject: [PATCH 19/21] Pipeline fix --- tests/openlp_plugins/songs/test_lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/openlp_plugins/songs/test_lib.py b/tests/openlp_plugins/songs/test_lib.py index 1116fbcc0..88d5838c1 100644 --- a/tests/openlp_plugins/songs/test_lib.py +++ b/tests/openlp_plugins/songs/test_lib.py @@ -359,7 +359,7 @@ def test_transpose_lyrics(mocked_transpose_verse, mock_settings): '---[Verse:2]---\n'\ 'I once was lost but now I\'m found.' mock_settings.value.return_value = 'english' - + mocked_transpose_verse.return_value = ['', None] # WHEN: Transposing the lyrics transpose_lyrics(lyrics, 1) From 123c0d0bc871dba6efed5230ebc750c6a07a38b8 Mon Sep 17 00:00:00 2001 From: Raoul Snyman Date: Sun, 1 Aug 2021 18:18:16 +0000 Subject: [PATCH 20/21] Apply 28 suggestion(s) to 2 file(s) --- openlp/plugins/songs/lib/__init__.py | 36 +++++++++++++------------- tests/openlp_plugins/songs/test_lib.py | 30 ++++++++++----------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index 0376dfeb0..a9e9f174e 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -584,8 +584,8 @@ def transpose_verse(verse_text, transpose_value, notation, key): # 6/9 chords should be noted 6-9 or 69 or 6add9 lyric_list = re.split(r'(\[|\]|/)', verse_text) transposed_lyrics = '' - isbass = False - lastchord = None + is_bass = False + last_chord = None in_tag = False for word in lyric_list: if not in_tag: @@ -597,15 +597,15 @@ def transpose_verse(verse_text, transpose_value, notation, key): in_tag = False transposed_lyrics += word elif word == '/': - isbass = True + is_bass = True transposed_lyrics += word elif word == '--}{--': transposed_lyrics += word else: # This MUST be a chord - transposed_chord, key, lastchord = transpose_chord(word, transpose_value, notation, key, lastchord, + transposed_chord, key, last_chord = transpose_chord(word, transpose_value, notation, key, last_chord, isbass) - isbass = False + is bass = False transposed_lyrics += transposed_chord # If still inside a chord tag something is wrong! if in_tag: @@ -614,7 +614,7 @@ def transpose_verse(verse_text, transpose_value, notation, key): return transposed_lyrics, key -def transpose_chord(chord, transpose_value, notation, key, lastchord, isbass): +def transpose_chord(chord, transpose_value, notation, key, last_chord, is_bass): """ Transpose chord according to the notation used. NOTE: This function has a javascript equivalent in chords.js - make sure to update both! @@ -754,7 +754,7 @@ def transpose_chord(chord, transpose_value, notation, key, lastchord, isbass): 'Labm': ['Rebb', 'Reb', 'Mibb', 'Mib', 'Fab', 'Solbb', 'Solb', 'Labb', 'Lab', 'Sibb', 'Sib', 'Dob'] } } - notenumbers = { + note_numbers = { 'german': { 'C': 0, 'H#': 0, 'B##': 0, 'Bx': 0, 'Dbb': 0, 'C#': 1, 'Db': 1, @@ -801,7 +801,7 @@ def transpose_chord(chord, transpose_value, notation, key, lastchord, isbass): chord = chord.replace('♭', 'b').replace('♯', '#') transposed_chord = '' minor = '' - thischordchangeskey = False + is_key_change_chord = False notes_sharp = notes_sharp_notation[notation] notes_flat = notes_flat_notation[notation] notes_preferred = ['b', '#', '#', 'b', '#', 'b', '#', '#', 'b', '#', 'b', '#'] @@ -815,7 +815,7 @@ def transpose_chord(chord, transpose_value, notation, key, lastchord, isbass): transposed_chord += '=' if len(chord) > 1: chord = chord[1:] - thischordchangeskey = True + is_key_change_chord = True else: chord = '' if chord and chord[0] == '|': @@ -844,28 +844,28 @@ def transpose_chord(chord, transpose_value, notation, key, lastchord, isbass): chord = chord[1:] if len(chord) > 1 else '' else: minor = '' - note_number = notenumbers[notation][note] + note_number = note_numbers[notation][note] note_number += transpose_value while note_number > 11: note_number -= 12 while note_number < 0: note_number += 12 - if isbass: - if lastchord: - note = scales[notation][lastchord][note_number] + if is_bass: + if last_chord: + note = scales[notation][last_chord][note_number] elif key: note = scales[notation][key][note_number] else: note = notes_sharp[note_number] if notes_preferred[note_number] == '#' else notes_flat[note_number] else: - if not key or thischordchangeskey: + if not key or is_key_change_chord: note = notes_sharp[note_number] if notes_preferred[note_number] == '#' else notes_flat[note_number] else: note = scales[notation][key][note_number] transposed_chord += note + minor + chord - if thischordchangeskey: + if is_key_change_chord: key = note + minor else: - if not isbass: - lastchord = note + minor - return transposed_chord, key, lastchord + if not is_bass: + last_chord = note + minor + return transposed_chord, key, last_chord diff --git a/tests/openlp_plugins/songs/test_lib.py b/tests/openlp_plugins/songs/test_lib.py index 88d5838c1..f97f76e8d 100644 --- a/tests/openlp_plugins/songs/test_lib.py +++ b/tests/openlp_plugins/songs/test_lib.py @@ -276,16 +276,16 @@ def test_transpose_chord_up(): # GIVEN: A Chord chord = 'C' key = None - lastchord = None - isbass = False + last_chord = None + is_bass = False # WHEN: Transposing it 1 up - new_chord, key, lastchord = transpose_chord(chord, 1, 'english', key, lastchord, isbass) + new_chord, key, last_chord = transpose_chord(chord, 1, 'english', key, last_chord, is_bass) # THEN: The chord should be transposed up one note assert new_chord == 'C#', 'The chord should be transposed up.' assert key is None, 'The key should not be set' - assert lastchord == 'C#', 'If not isbass, then lastchord should be returned' + assert last_chord == 'C#', 'If not is_bass, then last_chord should be returned' def test_transpose_chord_up_adv(): @@ -295,21 +295,21 @@ def test_transpose_chord_up_adv(): # GIVEN: An advanced Chord chord = '(D/F#)' key = None - lastchord = None - isbass = False - chordsplit = chord.split("/") + last_chord = None + is_bass = False + chord_split = chord.split("/") # WHEN: Transposing it 1 up - new_chord, key, lastchord = transpose_chord(chordsplit[0], 1, 'english', key, lastchord, isbass) + new_chord, key, last_chord = transpose_chord(chord_split[0], 1, 'english', key, last_chord, is_bass) # AFTER "/" isbass is true, lastchord is set - isbass = True - new_bass, key, lastchord = transpose_chord(chordsplit[1], 1, 'english', key, lastchord, isbass) + is_bass = True + new_bass, key, last_chord = transpose_chord(chord_split[1], 1, 'english', key, last_chord, is_bass) # THEN: The chord should be transposed up one note assert new_chord == '(Eb', 'The chord should be transposed up.' assert new_bass == 'G)', 'Bass should be transposed up.' assert key is None, 'no key should be defined' - assert lastchord == 'Eb', 'lastchord is generated' + assert last_chord == 'Eb', 'last_chord is generated' def test_transpose_chord_down(): @@ -319,16 +319,16 @@ def test_transpose_chord_down(): # GIVEN: A Chord chord = 'C' key = None - lastchord = None - isbass = False + last_chord = None + is_bass = False # WHEN: Transposing it 1 down - new_chord, key, lastchord = transpose_chord(chord, -1, 'english', key, lastchord, isbass) + new_chord, key, last_chord = transpose_chord(chord, -1, 'english', key, last_chord, is_bass) # THEN: The chord should be transposed down one note assert new_chord == 'B', 'The chord should be transposed down.' assert key is None, 'The key should not be set' - assert lastchord == 'B', 'If not isbass, then lastchord should be returned' + assert last_chord == 'B', 'If not is_bass, then last_chord should be returned' def test_transpose_chord_error(): From b9d317dedf3748f7752fcf016802e8d42553e49f Mon Sep 17 00:00:00 2001 From: STEPHANVS Date: Sun, 1 Aug 2021 20:54:25 +0200 Subject: [PATCH 21/21] Variable namings and pipeline fixes --- openlp/plugins/songs/lib/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openlp/plugins/songs/lib/__init__.py b/openlp/plugins/songs/lib/__init__.py index a9e9f174e..59b56fc5e 100644 --- a/openlp/plugins/songs/lib/__init__.py +++ b/openlp/plugins/songs/lib/__init__.py @@ -604,8 +604,8 @@ def transpose_verse(verse_text, transpose_value, notation, key): else: # This MUST be a chord transposed_chord, key, last_chord = transpose_chord(word, transpose_value, notation, key, last_chord, - isbass) - is bass = False + is_bass) + is_bass = False transposed_lyrics += transposed_chord # If still inside a chord tag something is wrong! if in_tag: