3 notesChars
= ['A', 'B', 'C', 'D', 'E', 'F', 'G']
6 def window(iterable
, size
=2):
9 for e
in range(0, size
):
16 def parseMelody(melodyString
, bpm
=120, transposeBySemitones
=0):
17 # parse string to python list
18 tokenizedNotes
= melodyString
.split(' ')
20 for token
, nextToken
in window(tokenizedNotes
+ [None], 2):
21 if token
.startswith(pauseChar
):
22 # Token is a pause operation, use frequency 0
23 operations
.append([0, getDurationInMs(bpm
, token
[1:])])
24 elif token
.startswith(tuple(notesChars
)):
25 # Token is a note; next token will be duration of this note
26 frequency
= getFrequency(token
, transposeBySemitones
)
27 duration
= getDurationInMs(bpm
, nextToken
)
28 operations
.append([frequency
, duration
])
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.0))
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(int(element
[0])) + "," + str(int(element
[1])) + "}")
53 return "{" + ','.join(elements
) + "}"
55 def parseToArray(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 external
.rtttl
import RTTTL
64 return RTTTL(melodyOrRTTTL
).notes()
66 def parse(melodyOrRTTTL
):
67 operations
= parseToArray(melodyOrRTTTL
)
68 return generateArrayString(operations
)
71 if __name__
== '__main__':
72 print(parse(sys
.argv
[1]))