diff --git a/src/tadam.py b/src/tadam.py new file mode 100755 index 0000000..8501b72 --- /dev/null +++ b/src/tadam.py @@ -0,0 +1,145 @@ +#!/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 +chunk_length = -1 + +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: + pysoundfile + + 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: + tadam -v -i raw -o exp -l 5 -z -p "Car910130-2021-Pass0-Z1-AudioMoth-247AA5015FDF286B-" -r 0.1 + """ + print(usage_str) + +def rate(infile, outfile, rate_ratio): + data, samplerate = sf.read(infile) + new_samplerate = int(samplerate * rate_ratio) + if (chunk_length != -1): + if verbose: + print(f"\t Splitting {infile} in {chunk_length}s-long chunks.") + sections = int(np.ceil(len(data) / samplerate / chunk_length)) + for i in range(sections): + if verbose: + print(f"\t {str(i).zfill(len(str(sections)))}/{sections} \t {outfile}") + filename = outfile.replace('.wav', f'-{str(i).zfill(len(str(sections)))}.wav') + temp = data[i*samplerate*chunk_length : i*samplerate*chunk_length+samplerate*chunk_length] + sf.write(filename, temp, samplerate) + else: + sf.write(outfile, data, new_samplerate) + +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: + outfile = prefix + infile.replace('.WAV', '.wav').replace('.wav', f'.exp_x{int(1/rate_ratio)}.wav') + if verbose: + 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) + +def zip_folder(outfolder): + if verbose: + print("Compressing .zip archive...") + with zipfile.ZipFile(f"{outfolder}.zip", 'w') as f: + for file in os.listdir(outfolder): + f.write(os.path.join(outfolder, file)) + if verbose: + print("Archive compressed.") + +def main(): + try: + opts, args = getopt.getopt(sys.argv[1:], "hi:o:vr:l:zp:", ["help", "input=", "output=", "verbose", "ratio=", "length=", "zip", "prefix="]) + except getopt.GetoptError as err: + print(err) + + global verbose + verbose = False + rate_ratio = 0.1 # Default is x10 time expansion + infolder = "raw" + outfolder = "exp" + compress = False + prefix = "" + + 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"): + global chunk_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) + if compress: + zip_folder(outfolder) + if verbose: + print("Done.") + +if __name__ == "__main__": + main() \ No newline at end of file