cli.py 5.15 KB
Newer Older
Matteo's avatar
update    
Matteo committed
1
2
import argparse
import os
Matteo's avatar
update    
Matteo committed
3
import sys
Matteo's avatar
update    
Matteo committed
4
from rich.console import Console
Matteo's avatar
update  
Matteo committed
5

Matteo's avatar
update    
Matteo committed
6
from mpai_cae_arp.types.irregularity import IrregularityFile, Source
Matteo's avatar
update    
Matteo committed
7
8
9
from mpai_cae_arp.files import File, FileType
from mpai_cae_arp.io import prettify, Style

Matteo's avatar
update    
Matteo committed
10
11
import audio_analyzer.segment_finder as sf
import audio_analyzer.classifier as cl
Matteo's avatar
Matteo committed
12

Matteo's avatar
update    
Matteo committed
13

Matteo's avatar
update    
Matteo committed
14
def get_args() -> tuple[str | None, str | None]:
Matteo's avatar
update    
Matteo committed
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    if len(sys.argv) > 1:
        parser = argparse.ArgumentParser(
            prog="audio-analyzer",
            formatter_class=argparse.RawDescriptionHelpFormatter,
            description=f"A tool that implements {prettify('MPAI CAE-ARP Audio Analyser', styles=[Style.BOLD])} Technical Specification.",
            epilog="For support, please contact Matteo Spanio <dev2@audioinnova.com>.\n"
                "This software is licensed under the GNU General Public License v3.0."
        )
        parser.add_argument("--working-directory", "-w", help="The path were the AIW will find and save the files")
        parser.add_argument("--files-name", "-f", help=f"The name of the files to be analyzed {prettify('without extension', styles=[Style.UNDERLINE])}")
        args = parser.parse_args()
        return args.working_directory, args.files_name
    else:
        return os.getenv("WORKING_DIRECTORY"), os.getenv("FILES_NAME")
Matteo's avatar
update    
Matteo committed
29

Matteo's avatar
update    
Matteo committed
30
31

def exit_with_error(error_message: str, console) -> None:
Matteo's avatar
update    
Matteo committed
32
    console.print(f"[red bold]Error: {error_message}")
Matteo's avatar
update    
Matteo committed
33
34
35
    quit(os.EX_USAGE)


Matteo's avatar
update    
Matteo committed
36
def main() -> None:
Matteo's avatar
update    
Matteo committed
37
    console = Console()
Matteo's avatar
update    
Matteo committed
38
    console.print("[bold]Welcome to ARP Audio Analyser!")
Matteo's avatar
update    
Matteo committed
39

Matteo's avatar
update    
Matteo committed
40
41
42
43
44
45
    working_directory, files_name = get_args()
    if any(map(lambda x: x is None, [working_directory, files_name])):
        exit_with_error("{}\n{}".format(
            "Working directory or files name not specified!",
            "Try -h/--help to know more about Audio Analyser usage"), console)

Matteo's avatar
update    
Matteo committed
46
    try:
Matteo's avatar
update    
Matteo committed
47
        os.makedirs(os.path.join(working_directory, "temp", files_name), exist_ok=True)
Matteo's avatar
update    
Matteo committed
48
49
    except:
        exit_with_error("Unable to create temporary directory, output path already exists", console)
Matteo's avatar
update    
Matteo committed
50
51
52
53
    
    with console.status("[purple]Reading input files", spinner="dots"):
        audio_src = os.path.join(working_directory, "PreservationAudioFile", f"{files_name}.wav")
        video_src = os.path.join(working_directory, "PreservationAudioVisualFile", f"{files_name}.mov")
Matteo's avatar
update    
Matteo committed
54
55
56
57
58
59
60
61

        audio_exists = os.path.exists(audio_src)
        video_exists = os.path.exists(video_src)

        match audio_exists, video_exists:
            case True, True:
                console.print("[green]Input files found!")
            case False, True:
Matteo's avatar
update    
Matteo committed
62
                exit_with_error("Audio file not found! :loud_sound:", console)
Matteo's avatar
update    
Matteo committed
63
            case True, False:
Matteo's avatar
update    
Matteo committed
64
                exit_with_error("Video file not found! :vhs:", console)
Matteo's avatar
update    
Matteo committed
65
            case False, False:
Matteo's avatar
update    
Matteo committed
66
                exit_with_error("Input files not found! :t-rex:", console)
Matteo's avatar
update    
Matteo committed
67
68

    # create irregularity file 1
Matteo's avatar
update    
Matteo committed
69
    with console.status("[purple]Creating irregularity file 1", spinner="dots"):
Matteo's avatar
update    
Matteo committed
70
        irreg1 = sf.create_irreg_file(audio_src, video_src)
Matteo's avatar
update    
Matteo committed
71
        console.log(f"Found {len(irreg1.irregularities)} irregularities from Audio source")
Matteo's avatar
update    
Matteo committed
72
        File(f"{working_directory}/temp/{files_name}/AudioAnalyser_IrregularityFileOutput1.json", FileType.JSON).write_content(irreg1.to_json())
Matteo's avatar
update    
Matteo committed
73
        console.log("[geen]Irregularity file 1 created")
Matteo's avatar
update    
Matteo committed
74
75

    # create irregularity file 2
Matteo's avatar
update    
Matteo committed
76
    with console.status("[purple]Creating irregularity file 2", spinner="dots"):
Matteo's avatar
update    
Matteo committed
77
78
79
80
        try:
            video_irreg_1 = File(f"{working_directory}/temp/{files_name}/VideoAnalyser_IrregularityFileOutput1.json", FileType.JSON).get_content()
        except:
            exit_with_error("Video irregularity file 1 not found", console)
Matteo's avatar
update    
Matteo committed
81
        console.log("Video irregularity file 1 found")
Matteo's avatar
update    
Matteo committed
82
        irreg2 = sf.merge_irreg_files(irreg1, IrregularityFile.from_json(video_irreg_1))
Matteo's avatar
update    
Matteo committed
83
        console.log("[geen]Irregularity file 2 created")
Matteo's avatar
update    
Matteo committed
84

Matteo's avatar
update    
Matteo committed
85
    with console.status("[cyan]Extracting audio irregularities", spinner="dots"):
Matteo's avatar
update    
Matteo committed
86
        irreg2= sf.extract_audio_irregularities(audio_src, irreg2, working_directory + "/temp/" + files_name)
Matteo's avatar
update    
Matteo committed
87
        console.log("[green]Audio irregularities extracted")
Matteo's avatar
update    
Matteo committed
88
89

    # classify audio irregularities
Matteo's avatar
update    
Matteo committed
90
    with console.status("[cyan bold]Classifying audio irregularities", spinner="monkey"):
Matteo's avatar
update    
Matteo committed
91
92
93
94
95
96
97
98
99
100
101
        irregularities_features = cl.extract_features(irreg2.irregularities)
        console.log("[green]Audio irregularities features extracted")
        classification_results = cl.classify(irregularities_features)
        console.log("[green]Audio irregularities classified")

    with console.status("[purple]Updating irregularity file 2", spinner="dots"):
        for irreg, classification_result in zip(irreg2.irregularities, classification_results):
            if irreg.source == Source.AUDIO:
                irreg.irregularity_type = classification_result.get_irregularity_type()
                irreg.irregularity_properties = classification_result if classification_result.get_irregularity_type() is not None else None

Matteo's avatar
update    
Matteo committed
102
    File(f"{working_directory}/temp/{files_name}/AudioAnalyser_IrregularityFileOutput2.json", FileType.JSON).write_content(irreg2.to_json())
Matteo's avatar
update    
Matteo committed
103

Matteo's avatar
update    
Matteo committed
104
105
    console.print("[green bold]Success! :tada:")
    quit(os.EX_OK)
Matteo's avatar
update    
Matteo committed
106
107


Matteo's avatar
update  
Matteo committed
108
if __name__ == "__main__":
Matteo's avatar
update    
Matteo committed
109
    main()