~alisonken1/openlp/pjlink2-f

« back to all changes in this revision

Viewing changes to openlp/plugins/songs/lib/__init__.py

  • Committer: Tim Bentley
  • Author(s): Tomas Groth
  • Date: 2017-05-17 20:30:47 UTC
  • mfrom: (2587.3.78 chords)
  • Revision ID: tim.bentley@gmail.com-20170517203047-o11dl9bfu3re2tu0
Added support for chords in Chord Pro format (using brackets), with support for chord transposing and 3 different notations.
Added support for import of song in ChordPro file format
Added support for importing chords and verseorder from songbeamer.
Add support for export and import of chords in openlyrics
Added support for importing chords from opensong.
Added support for importing chords from videopsalm.
Added support for printing chords.

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
 
30
30
from PyQt5 import QtWidgets
31
31
 
32
 
from openlp.core.common import AppLocation, CONTROL_CHARS
 
32
from openlp.core.common import AppLocation, CONTROL_CHARS, Settings
33
33
from openlp.core.lib import translate, clean_tags
34
34
from openlp.plugins.songs.lib.db import Author, MediaFile, Song, Topic
35
35
from openlp.plugins.songs.lib.ui import SongStrings
380
380
    if isinstance(song.lyrics, bytes):
381
381
        song.lyrics = str(song.lyrics, encoding='utf8')
382
382
    verses = SongXML().get_verses(song.lyrics)
383
 
    song.search_lyrics = ' '.join([clean_string(clean_tags(verse[1])) for verse in verses])
 
383
    song.search_lyrics = ' '.join([clean_string(clean_tags(verse[1], True)) for verse in verses])
384
384
    # The song does not have any author, add one.
385
385
    if not song.authors_songs:
386
386
        name = SongStrings.AuthorUnknown
541
541
    except OSError:
542
542
        log.exception('Could not remove directory: {path}'.format(path=save_path))
543
543
    song_plugin.manager.delete_object(Song, song_id)
 
544
 
 
545
 
 
546
def transpose_lyrics(lyrics, transepose_value):
 
547
    """
 
548
    Transepose lyrics
 
549
 
 
550
    :param lyrcs: The lyrics to be transposed
 
551
    :param transepose_value: The value to transpose the lyrics with
 
552
    :return: The transposed lyrics
 
553
    """
 
554
    # Split text by verse delimiter - both normal and optional
 
555
    verse_list = re.split('(---\[.+?:.+?\]---|\[---\])', lyrics)
 
556
    transposed_lyrics = ''
 
557
    notation = Settings().value('songs/chord notation')
 
558
    for verse in verse_list:
 
559
        if verse.startswith('---[') or verse == '[---]':
 
560
            transposed_lyrics += verse
 
561
        else:
 
562
            transposed_lyrics += transpose_verse(verse, transepose_value, notation)
 
563
    return transposed_lyrics
 
564
 
 
565
 
 
566
def transpose_verse(verse_text, transepose_value, notation):
 
567
    """
 
568
    Transepose lyrics
 
569
 
 
570
    :param lyrcs: The lyrics to be transposed
 
571
    :param transepose_value: The value to transpose the lyrics with
 
572
    :return: The transposed lyrics
 
573
    """
 
574
    if '[' not in verse_text:
 
575
        return verse_text
 
576
    # Split the lyrics based on chord tags
 
577
    lyric_list = re.split('(\[|\]|/)', verse_text)
 
578
    transposed_lyrics = ''
 
579
    in_tag = False
 
580
    for word in lyric_list:
 
581
        if not in_tag:
 
582
            transposed_lyrics += word
 
583
            if word == '[':
 
584
                in_tag = True
 
585
        else:
 
586
            if word == ']':
 
587
                in_tag = False
 
588
                transposed_lyrics += word
 
589
            elif word == '/':
 
590
                transposed_lyrics += word
 
591
            else:
 
592
                # This MUST be a chord
 
593
                transposed_lyrics += transpose_chord(word, transepose_value, notation)
 
594
    # If still inside a chord tag something is wrong!
 
595
    if in_tag:
 
596
        return verse_text
 
597
    else:
 
598
        return transposed_lyrics
 
599
 
 
600
 
 
601
def transpose_chord(chord, transpose_value, notation):
 
602
    """
 
603
    Transpose chord according to the notation used.
 
604
    NOTE: This function has a javascript equivalent in chords.js - make sure to update both!
 
605
 
 
606
    :param chord: The chord to transpose.
 
607
    :param transpose_value: The value the chord should be transposed.
 
608
    :param notation: The notation to use when transposing.
 
609
    :return: The transposed chord.
 
610
    """
 
611
    # See https://en.wikipedia.org/wiki/Musical_note#12-tone_chromatic_scale
 
612
    notes_sharp_notation = {}
 
613
    notes_flat_notation = {}
 
614
    notes_sharp_notation['german'] = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'H']
 
615
    notes_flat_notation['german'] = ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'A', 'B', 'H']
 
616
    notes_sharp_notation['english'] = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B']
 
617
    notes_flat_notation['english'] = ['C', 'Db', 'D', 'Eb', 'Fb', 'F', 'Gb', 'G', 'Ab', 'A', 'Bb', 'B']
 
618
    notes_sharp_notation['neo-latin'] = ['Do', 'Do#', 'Re', 'Re#', 'Mi', 'Fa', 'Fa#', 'Sol', 'Sol#', 'La', 'La#', 'Si']
 
619
    notes_flat_notation['neo-latin'] = ['Do', 'Reb', 'Re', 'Mib', 'Fab', 'Fa', 'Solb', 'Sol', 'Lab', 'La', 'Sib', 'Si']
 
620
    chord_split = chord.replace('♭', 'b').split('/')
 
621
    transposed_chord = ''
 
622
    last_chord = ''
 
623
    notes_sharp = notes_sharp_notation[notation]
 
624
    notes_flat = notes_flat_notation[notation]
 
625
    notes_preferred = ['b', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#', '#']
 
626
    for i in range(0, len(chord_split)):
 
627
        if i > 0:
 
628
            transposed_chord += '/'
 
629
        currentchord = chord_split[i]
 
630
        if currentchord and currentchord[0] == '(':
 
631
            transposed_chord += '('
 
632
            if len(currentchord) > 1:
 
633
                currentchord = currentchord[1:]
 
634
            else:
 
635
                currentchord = ''
 
636
        if len(currentchord) > 0:
 
637
            if len(currentchord) > 1:
 
638
                if '#b'.find(currentchord[1]) == -1:
 
639
                    note = currentchord[0:1]
 
640
                    rest = currentchord[1:]
 
641
                else:
 
642
                    note = currentchord[0:2]
 
643
                    rest = currentchord[2:]
 
644
            else:
 
645
                note = currentchord
 
646
                rest = ''
 
647
            notenumber = notes_flat.index(note) if note not in notes_sharp else notes_sharp.index(note)
 
648
            notenumber += transpose_value
 
649
            while notenumber > 11:
 
650
                notenumber -= 12
 
651
            while notenumber < 0:
 
652
                notenumber += 12
 
653
            if i == 0:
 
654
                current_chord = notes_sharp[notenumber] if notes_preferred[notenumber] == '#' else notes_flat[
 
655
                    notenumber]
 
656
                last_chord = current_chord
 
657
            else:
 
658
                current_chord = notes_flat[notenumber] if last_chord not in notes_sharp else notes_sharp[notenumber]
 
659
            if not (note not in notes_flat and note not in notes_sharp):
 
660
                transposed_chord += current_chord + rest
 
661
            else:
 
662
                transposed_chord += note + rest
 
663
    return transposed_chord