-
Notifications
You must be signed in to change notification settings - Fork 0
/
menv.py
171 lines (140 loc) · 4.92 KB
/
menv.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#!/usr/bin/env python
"""
Python Command Line Musical Interpreter for PySynth.
Pranav Ravichandran (me@onloop.net)
"""
import play_wav
import pysynth, pysynth_b, pysynth_s
import wave
import sys
import os
import string
assert sys.version >= '3.3', "This program does not work with older versions of Python.\
Please install Python 3.3 or later."
#Type 'help' to access.
helpContent = "------------------------------\nPySynth musical note interpreter.\nUsage: <Duration><Note> <Duration2><Note2> .... <DurationN><NoteN>\nOptional arguments:\n\t--bpm=Beats per minute [Default:120]\n\t--repeat=Number of bars [Default:1]\n\t--sound=Instrument [a = Flute/Organ, b = piano, s = plucked string, Default = a]\n\t--save=filename (Filename to save the file to. Appends .wav to filename)\nSamples:\n8g 8g 8g 2eb 8r 8f 8f 8f 1d --sound=a\n4e4 4e4 4f4 4g4 4g4 4f4 4e4 4d4 4c4 4c4 4d4 4e4 4e4 4d4 2d4 4e4 4e4 4f4 4g4 4g4 4f4 4e4 4d4 4c4 4c4 4d4 4e4 4d4 4c4 2c4 --bpm=200 --repeat=1 --sound=s --save=Ode_to_Joy\nCommands: 'exit' and 'help'\n------------------------------"
usageHelp = "Notes are 'a' through 'g' of course,\noptionally with '#' or 'b' appended for sharps or flats.\nFinally the octave number (defaults to octave 4 if not given).\nAn asterisk at the end makes the note a little louder (useful for the beat).\n'r' is a rest.\n\nNote value is a number:\n1=Whole Note; 2=Half Note; 4=Quarter Note, etc.\nDotted notes can be written in two ways:\n1.33 = -2 = dotted half\n2.66 = -4 = dotted quarter\n5.33 = -8 = dotted eighth\n--------------------------------"
warningStr = "Improper Syntax - Type 'help' to see usage."
invalidCmd = "Command does not exist."
invalidOption = "Invalid Option."
class mEnv:
cliInput = ''
synthParam = []
bpmVal = 0
repeatVal = 0
inputEntered = False
instrument = ''
outFile = ''
trashFile = True
def __init__(self):
''' Constructor class. '''
# Get the user input.
cliInput = input(">>> ")
self.parse(cliInput)
# Different cases of input, when optional argument 'sound' is given.
if self.instrument == 'a' or self.instrument == '':
self.synthSounds(pysynth, self.outFile)
elif self.instrument == 'b':
self.synthSounds(pysynth_b, self.outFile)
elif self.instrument == 's':
self.synthSounds(pysynth_s, self.outFile)
else:
print(invalidOption)
mEnv()
def parse(self, cliInput):
''' Parse command line input.'''
# 'exit' command.
if cliInput == 'exit':
sys.exit()
# 'help' command.
if cliInput == 'help':
print('\n' + helpContent + '\n' + usageHelp + '\n')
mEnv()
# List with whitespace as delimiter.
cliInput = cliInput.split()
self.synthParam = []
for comp in cliInput:
# Optional arguments.
if comp.startswith('--'):
comp = comp.strip('-')
comp = comp.split('=')
if comp[0] == 'bpm':
try:
self.bpmVal = int(comp[1])
except IndexError:
print(warningStr)
mEnv()
elif comp[0] == 'repeat':
try:
self.repeatVal = int(comp[1])
except IndexError:
print(warningStr)
mEnv()
elif comp[0] == 'sound':
try:
self.instrument = str(comp[1])
except IndexError:
print(warningStr)
mEnv()
elif comp[0] == 'save':
try:
self.outFile = str(comp[1]) + '.wav'
self.trashFile = False
except IndexError:
print(warningStr)
mEnv()
continue
# Notes and beats.
i = 0
for alphanum in comp:
if alphanum.isalpha():
try:
self.synthParam.append((comp[i:], int(comp[:i])))
except ValueError:
print(invalidCmd)
mEnv()
break
i += 1
def play(self, outFile):
''' Open the .wav file and play it.'''
if outFile == '':
outFile = 'temp.wav'
a = play_wav.Sound()
a.playFile(outFile)
def removeFile(self, outFile):
''' Delete the .wav file.'''
if outFile == '':
outFile = 'temp.wav'
if self.trashFile:
os.remove(outFile)
def synthSounds(self, renderSound, outFile):
''' Render sound with pysynth_a, pysynth_b or pysynth_s based on user preference.'''
if outFile == '':
outFile = 'temp.wav'
try:
# Different cases of input, when optional arguments 'bpm' and 'repeat' are given.
if self.bpmVal and self.repeatVal:
renderSound.make_wav(self.synthParam, fn = outFile, silent = True, bpm = self.bpmVal, repeat = self.repeatVal)
elif self.bpmVal:
renderSound.make_wav(self.synthParam, fn = outFile, silent = True, bpm = self.bpmVal)
elif self.repeatVal:
renderSound.make_wav(self.synthParam, fn = outFile, silent = True, repeat = self.repeatVal)
else:
renderSound.make_wav(self.synthParam, fn = outFile, silent = True)
except KeyError:
print(warningStr)
mEnv()
if __name__ == "__main__":
# Print introductory help content.
print(helpContent)
# Interpreter loop.
while True:
a = mEnv()
try:
a.play(a.outFile)
except:
a.trashFile = False
if a.outFile == '':
a.outFile = 'temp.wav'
print('Could not play file. Saved to ' + a.outFile)
a.removeFile(a.outFile)