-
Notifications
You must be signed in to change notification settings - Fork 2
/
pyARSS.py
174 lines (142 loc) · 6.4 KB
/
pyARSS.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
172
173
174
from subprocess import run, PIPE
from pydub import AudioSegment
from platform import system
from os import path as pth
from uuid import uuid4
from os import remove
sys = system()
supported = ["Windows", "Linux", "Darwin"]
if sys not in supported:
raise RuntimeError("Invalid operating system. pyARSS only supports Windows, MacOS and Linux")
# Set ARSS run command for the correct platform
modpth = pth.abspath(__file__)
moddir = pth.dirname(modpth)
if sys == "Windows":
cmd = moddir + "\\bin_windows\\arss"
elif sys == "Linux":
cmd = moddir + "/bin_linux/arss"
else:
cmd = "arss" # MacOS requires ARSS to be directly installed via the installer.
# Encodes audio file `input_path` into image file `output_path` using ARSS.
def Encode(input_path : str, output_path : str,
min_frequency = 27,
max_frequency = 20000,
pps = 100,
bpo = 48):
# Change paths to absolute paths to avoid errors with ARSS.
input_path = pth.abspath(input_path)
output_path = pth.abspath(output_path)
uuid = None
if not input_path.endswith(".wav"):
# Assume we need to convert the file.
if not input_path.endswith(".mp3"):
# Validate input_path input.
# Raise an error if the user inputted an invalid file type.
if "." in input_path:
raise ValueError("The input_path must be a WAV file or an MP3 file.")
# Raise an error if the user inputted a directory.
elif input_path[-1] in ["\\", "/"]:
raise ValueError("The input_path must be a file path, not a directory.")
# Raise generic error.
else:
raise ValueError("The input_path must contain a path to an MP3 or WAV file.")
# Generate temporary WAV file from MP3.
new = AudioSegment.from_mp3(input_path)
uuid = "_pyARSS_temp_" + uuid4().hex + ".wav"
new.export(uuid, format="wav")
# Validate output_path input.
if not output_path.endswith(".bmp"):
# Raise an error if the user inputted an invalid file type.
if "." in output_path:
raise ValueError("The output_path must be a BMP file.")
# Raise an error if the user inputted a directory.
elif output_path[-1] in ["\\", "/"]:
raise ValueError("The output_path must be a file path, not a directory.")
# Raise generic error.
else:
raise ValueError("The output_path must contain a path to the new BMP file.")
# Run the main ARSS executable.
result = run([
cmd, "-q",
pth.abspath(uuid) if uuid is not None \
else input_path, # Input file
output_path, # Output file
"--analysis", # Type
"--min-freq", str(min_frequency), # Minimum frequency
"--max-freq", str(max_frequency), # Maximum frequency
"--pps", str(pps), # Time resolution (pixels per second)
"--bpo", str(bpo) # Frequency resolution (bands per octave)
], stderr=PIPE, universal_newlines=True)
# Remove temporary WAV file.
if uuid is not None:
remove(uuid)
# Check and raise ARSS errors.
if result.returncode != 0:
raise RuntimeError(result.stderr)
# Decodes image file `input_path` into audio file `output_path` using ARSS.
def Decode(input_path : str, output_path : str,
min_frequency = 27,
max_frequency = 20000,
sample_rate = 44100,
sine = True,
pps = 100,
bpo = 48):
# Change paths to absolute paths to avoid errors with ARSS.
input_path = pth.abspath(input_path)
output_path = pth.abspath(output_path)
# Validate input_path input.
if not input_path.endswith(".bmp"):
# Raise an error if the user inputted an invalid file type.
if "." in input_path:
raise ValueError("The input_path must be a BMP file.")
# Raise an error if the user inputted a directory.
elif input_path[-1] in ["\\", "/"]:
raise ValueError("The input_path must be a file path, not a directory.")
# Raise generic error.
else:
raise ValueError("The input_path must contain a path to the BMP file.")
# Validate output_path input.
if not output_path.endswith(".wav") and not output_path.endswith(".mp3"):
# Raise an error if the user inputted an invalid file type.
if "." in output_path:
raise ValueError("The output_path must be a WAV file or an MP3 file.")
# Raise an error if the user inputted a directory.
elif output_path[-1] in ["\\", "/"]:
raise ValueError("The output_path must be a file path, not a directory.")
# Raise generic error.
else:
raise ValueError("The output_path must contain a path to an MP3 or WAV file.")
# Should pyARSS create a temporary WAV file?
# ARSS only supports waveform files.
if not output_path.endswith(".wav"):
uuid = "_pyARSS_temp_" + uuid4().hex + ".wav"
else:
uuid = None
# Run the main ARSS executable.
result = run([
cmd, "-q",
input_path, # Input file
pth.abspath(uuid) if uuid is not None \
else output_path, # Output file
"--sine" if sine else "--noise", # Type
"--sample-rate", str(sample_rate), # Sample rate
"--min-freq", str(min_frequency), # Minimum frequency
# "--max-freq", str(max_frequency), # Maximum frequency -- TODO: ARSS: "You have set one parameter too many"
"--pps", str(pps), # Time resolution (pixels per second)
"--bpo", str(bpo) # Frequency resolution (bands per octave)
], stderr=PIPE, universal_newlines=True)
# Raise error if ARSS failed.
if result.returncode != 0:
try:
# Attempt to remove the temporary WAV file if it was generated.
remove(uuid)
except:
pass
raise RuntimeError(result.stderr)
# Convert the file if required.
if uuid is not None:
# Load WAV and convert MP3.
new = AudioSegment.from_wav(uuid)
new.export(output_path, format="mp3")
# Remove temporary WAV file.
remove(uuid)