2021-05-17 14:21:33 +02:00
|
|
|
#!/usr/bin/python3
|
|
|
|
"""
|
|
|
|
Tadam !
|
|
|
|
|
|
|
|
Tool to preprocess audio in real time from folder coming from recorder SD card
|
|
|
|
into time expansion audio splitted in 5s-long chunks to be sent to Vigie-Chiro.
|
|
|
|
"""
|
|
|
|
|
|
|
|
__author__ = "Samuel ORTION"
|
|
|
|
__copyright__ = "Copyright 2021, Chiro-Canto organisation"
|
|
|
|
__credits__ = ["Samuel ORTION"]
|
|
|
|
|
|
|
|
__license__ = "GPL"
|
|
|
|
__version__ = "1.0.0"
|
|
|
|
__maintainer__ = "Samuel ORTION"
|
|
|
|
__email__ = "samuel.ortion@orange.fr"
|
|
|
|
__status__ = "Production"
|
|
|
|
__date__ = "2021-05-17"
|
|
|
|
|
|
|
|
import soundfile as sf
|
|
|
|
import os
|
|
|
|
import sys
|
|
|
|
import numpy as np
|
|
|
|
import getopt
|
|
|
|
import zipfile
|
|
|
|
|
|
|
|
verbose = False
|
|
|
|
|
2022-07-15 14:50:24 +02:00
|
|
|
|
2021-05-17 14:21:33 +02:00
|
|
|
def usage():
|
|
|
|
usage_str = """
|
|
|
|
|
|
|
|
Tadam !
|
|
|
|
|
|
|
|
Tool to preprocess audio in real time from folder coming from recorder SD card
|
|
|
|
into time expansion audio splitted in 5s-long chunks to be sent to Vigie-Chiro.
|
|
|
|
|
|
|
|
|
|
|
|
Author: Samuel ORTION
|
|
|
|
License: GNU GPL v3 or later
|
|
|
|
|
|
|
|
Requirements:
|
2021-07-13 10:41:10 +02:00
|
|
|
pysoundfile, numpy
|
2021-05-17 14:21:33 +02:00
|
|
|
|
|
|
|
Usage:
|
|
|
|
./tadam.py -i INPUT_FOLDER [ -o OUTPUT_FOLDER ]
|
|
|
|
|
|
|
|
Available options:
|
|
|
|
-v (--verbose) - Verbose mode
|
|
|
|
-h (--help) - Display usage
|
|
|
|
-i (--input) - Specify input folder
|
|
|
|
-o (--output) - Specify output folder
|
|
|
|
-l (--length) - Specify the max length (in seconds) of output wav
|
|
|
|
-z (--zip) - Specify wether the output folder has to be compressed
|
|
|
|
-p (--prefix) - Specify the prefix that will be added to the output file name
|
|
|
|
-r (--ratio) - Specify samplerate convertion rate
|
|
|
|
|
|
|
|
Example:
|
2021-07-13 10:41:10 +02:00
|
|
|
tadam -v -i raw -o exp -l 5 -z -p "Car910130-2021-Pass1-Z1-AudioMoth_" -r 0.1
|
2021-05-17 14:21:33 +02:00
|
|
|
"""
|
|
|
|
print(usage_str)
|
|
|
|
|
2022-07-15 14:50:24 +02:00
|
|
|
|
2021-05-17 14:21:33 +02:00
|
|
|
def rate(infile, outfile, rate_ratio):
|
|
|
|
data, samplerate = sf.read(infile)
|
|
|
|
new_samplerate = int(samplerate * rate_ratio)
|
2021-07-13 10:41:10 +02:00
|
|
|
sf.write(outfile, data, new_samplerate)
|
2021-05-17 14:21:33 +02:00
|
|
|
|
2022-07-15 14:50:24 +02:00
|
|
|
|
2021-05-17 14:21:33 +02:00
|
|
|
def convert_folder(infolder, outfolder, rate_ratio, prefix):
|
|
|
|
try:
|
|
|
|
os.mkdir(outfolder)
|
|
|
|
except:
|
|
|
|
print(f"output folder {outfolder} exists.")
|
|
|
|
infiles = os.listdir(infolder)
|
|
|
|
n = len(infiles)
|
|
|
|
i = 1
|
|
|
|
for infile in infiles:
|
2022-07-15 14:50:24 +02:00
|
|
|
extension = infile.split(".")[-1]
|
|
|
|
if not extension in ["wav", "WAV"]:
|
|
|
|
continue
|
2021-07-13 10:41:10 +02:00
|
|
|
outfile = prefix + infile.replace('.WAV', '.wav')
|
2021-05-17 14:21:33 +02:00
|
|
|
if verbose:
|
2022-07-15 14:50:24 +02:00
|
|
|
print(
|
|
|
|
f"{str(i).zfill(len(str(n)))}/{n} Processing {infile} → {outfile}...")
|
|
|
|
rate(os.path.join(infolder, infile),
|
|
|
|
os.path.join(outfolder, outfile), rate_ratio)
|
2021-07-13 10:41:10 +02:00
|
|
|
i += 1
|
2021-05-17 14:21:33 +02:00
|
|
|
|
2022-07-15 14:50:24 +02:00
|
|
|
|
2021-07-13 10:41:10 +02:00
|
|
|
def chunk(outfolder, length):
|
|
|
|
for file in os.listdir(outfolder):
|
|
|
|
infile = os.path.join(outfolder, file)
|
2022-07-15 14:50:24 +02:00
|
|
|
extension = infile.split(".")[-1]
|
|
|
|
if not extension in ["wav", "WAV"]:
|
|
|
|
continue
|
2021-07-13 10:41:10 +02:00
|
|
|
data, samplerate = sf.read(infile)
|
|
|
|
if verbose:
|
|
|
|
print(f"\t Splitting {infile} in {length}s-long chunks.")
|
|
|
|
sections = int(np.ceil(len(data) / samplerate / length))
|
|
|
|
for i in range(sections):
|
|
|
|
if verbose:
|
2022-07-15 14:50:24 +02:00
|
|
|
print(
|
|
|
|
f"\t {str(i).zfill(len(str(sections)))}/{sections} \t {infile}")
|
2021-07-13 10:41:10 +02:00
|
|
|
filename = infile.replace('.wav', f'_{str(i).zfill(3)}.wav')
|
2022-07-15 14:50:24 +02:00
|
|
|
temp = data[i*samplerate*length: i *
|
|
|
|
samplerate*length+samplerate*length]
|
2021-07-13 10:41:10 +02:00
|
|
|
sf.write(filename, temp, samplerate)
|
|
|
|
os.remove(infile)
|
2022-07-15 14:50:24 +02:00
|
|
|
|
2021-05-17 14:21:33 +02:00
|
|
|
def zip_folder(outfolder):
|
|
|
|
if verbose:
|
|
|
|
print("Compressing .zip archive...")
|
2021-07-13 10:41:10 +02:00
|
|
|
os.system('7z -v700m a output.zip exp')
|
2021-05-17 14:21:33 +02:00
|
|
|
if verbose:
|
|
|
|
print("Archive compressed.")
|
|
|
|
|
|
|
|
def main():
|
|
|
|
try:
|
2022-07-15 14:50:24 +02:00
|
|
|
opts, args = getopt.getopt(sys.argv[1:], "hi:o:vr:l:zp:", [
|
|
|
|
"help", "input=", "output=", "verbose", "ratio=", "length=", "zip", "prefix="])
|
2021-05-17 14:21:33 +02:00
|
|
|
except getopt.GetoptError as err:
|
|
|
|
print(err)
|
2022-07-15 14:50:24 +02:00
|
|
|
|
2021-05-17 14:21:33 +02:00
|
|
|
global verbose
|
2022-07-15 14:50:24 +02:00
|
|
|
verbose = False
|
|
|
|
rate_ratio = 0.1 # Default is x10 time expansion
|
2021-05-17 14:21:33 +02:00
|
|
|
infolder = "raw"
|
|
|
|
outfolder = "exp"
|
|
|
|
compress = False
|
|
|
|
prefix = ""
|
2021-07-13 10:41:10 +02:00
|
|
|
chunk_length = -1
|
2021-05-17 14:21:33 +02:00
|
|
|
|
|
|
|
for o, a in opts:
|
|
|
|
if o in ("-v", "--verbose"):
|
|
|
|
verbose = True
|
|
|
|
elif o in ("-h", "--help"):
|
|
|
|
usage()
|
|
|
|
sys.exit()
|
|
|
|
elif o in ("-i", "--input"):
|
|
|
|
infolder = a
|
|
|
|
elif o in ("-o", "--output"):
|
|
|
|
outfolder = a
|
|
|
|
elif o in ("-r", "--ratio"):
|
|
|
|
rate_ratio = float(a)
|
|
|
|
elif o in ("-l", "--length"):
|
|
|
|
chunk_length = int(a)
|
|
|
|
elif o in ("-z", "--zip"):
|
|
|
|
compress = True
|
|
|
|
elif o in ("-p", "--prefix"):
|
|
|
|
prefix = a
|
|
|
|
else:
|
|
|
|
assert False, "unhandled option"
|
|
|
|
convert_folder(infolder, outfolder, rate_ratio, prefix)
|
2021-07-13 10:41:10 +02:00
|
|
|
if chunk_length != -1:
|
|
|
|
chunk(outfolder, chunk_length)
|
2021-05-17 14:21:33 +02:00
|
|
|
if compress:
|
|
|
|
zip_folder(outfolder)
|
|
|
|
if verbose:
|
|
|
|
print("Done.")
|
2022-07-15 14:50:24 +02:00
|
|
|
|
2021-05-17 14:21:33 +02:00
|
|
|
if __name__ == "__main__":
|
2022-07-15 14:50:24 +02:00
|
|
|
main()
|