1 notesChars
= ['A', 'B', 'C', 'D', 'E', 'F', 'G']
4 def window(iterable
, size
=2):
7 for e
in range(0, size
):
14 def parseMelody(melodyString
, bpm
=120, transposeBySemitones
=0):
15 # parse string to python list
16 tokenizedNotes
= melodyString
.split(' ')
18 for token
, nextToken
in window(tokenizedNotes
+ [None], 2):
19 if token
.startswith(pauseChar
):
20 # Token is a pause operation, use frequency 0
21 operations
.append([0, getDurationInMs(bpm
, token
[1:])])
22 elif token
.startswith(tuple(notesChars
)):
23 # Token is a note; next token will be duration of this note
24 frequency
= getFrequency(token
, transposeBySemitones
)
25 duration
= getDurationInMs(bpm
, nextToken
)
26 operations
.append([frequency
, duration
])
29 # turn list into C-style array string
30 arrayString
= generateArrayString(operations
)
33 def getFrequency(note
, transposeBy
=0, A4
=440):
34 # example note: A#5, meaning: 5th octave A sharp
35 notes
= ['A', 'A#', 'B', 'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#']
36 octave
= int(note
[2]) if len(note
) == 3 else int(note
[1])
37 keyNumber
= notes
.index(note
[0:-1])
39 keyNumber
= keyNumber
+ 12 + ((octave
- 1) * 12) + 1
41 keyNumber
= keyNumber
+ ((octave
- 1) * 12) + 1
42 keyNumber
+= transposeBy
43 return int(A4
* 2 ** ((keyNumber
- 49) / 12))
45 def getDurationInMs(bpm
, duration
):
46 return int((1000 * (60 * 4 / bpm
)) / float(duration
))
48 def generateArrayString(melodyArray
):
49 # generate C-style array string from python list
51 for element
in melodyArray
:
52 elements
.append("{" + str(element
[0]) + "," + str(element
[1]) + "}")
53 return "{" + ','.join(elements
) + "}"
55 def parse(melodyOrRTTTL
):
56 # If | in melody it is original notes|bpm|transpose format
57 if ('|' in melodyOrRTTTL
):
58 defineValue
= melodyOrRTTTL
.split("|")
59 transposeBySemitones
= int(defineValue
[2]) if len(defineValue
) > 2 else 0
60 return parseMelody(defineValue
[0].strip(), int(defineValue
[1]), transposeBySemitones
)
63 from rtttl
import RTTTL
65 tune
= RTTTL(melodyOrRTTTL
)
66 for freq
, msec
in tune
.notes():
67 retVal
+= f
"{{{freq:.0f},{msec:.0f}}},"
70 retVal
= "{" + retVal
[:-1] + "}"
72 raise ValueError("Blank RTTTL melody detected")