/
checker.py
142 lines (119 loc) · 4.26 KB
/
checker.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
# -*- coding: utf-8 -*-
"""
Matchering - Audio Matching and Mastering Python Library
Copyright (C) 2016-2022 Sergree
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
"""
import numpy as np
from resampy import resample
from .log import Code, warning, info, debug, ModuleError
from . import Config
from .dsp import size, is_mono, is_stereo, mono_to_stereo, count_max_peaks
from .utils import time_str
def __check_sample_rate(
array: np.ndarray,
sample_rate: int,
required_sample_rate: int,
name: str,
log_handler,
log_code: Code,
) -> (np.ndarray, int):
if sample_rate != required_sample_rate:
debug(
f"Resampling {name} audio from {sample_rate} Hz to {required_sample_rate} Hz..."
)
array = resample(array, sample_rate, required_sample_rate, axis=0)
log_handler(log_code)
return array, required_sample_rate
def __check_length(
array: np.ndarray,
sample_rate: int,
max_length: int,
min_length: int,
name: str,
error_code_max: Code,
error_code_min: Code,
) -> None:
length = size(array)
debug(f"{name} audio length: {length} samples ({time_str(length, sample_rate)})")
if length > max_length:
raise ModuleError(error_code_max)
elif length < min_length:
raise ModuleError(error_code_min)
def __check_channels(
array: np.ndarray, info_code_mono: Code, error_code_not_stereo: Code
) -> np.ndarray:
if is_mono(array):
info(info_code_mono)
array = mono_to_stereo(array)
elif not is_stereo(array):
raise ModuleError(error_code_not_stereo)
return array
def __check_clipping_limiting(
array: np.ndarray,
clipping_samples_threshold: int,
limited_samples_threshold: int,
warning_code_clipping: Code,
warning_code_limiting: Code,
) -> None:
max_value, max_count = count_max_peaks(array)
if max_count > clipping_samples_threshold:
if np.isclose(max_value, 1.0):
warning(warning_code_clipping)
elif max_count > limited_samples_threshold:
warning(warning_code_limiting)
def check(
array: np.ndarray, sample_rate: int, config: Config, name: str
) -> (np.ndarray, int):
name = name.upper()
__check_length(
array,
sample_rate,
config.max_length * sample_rate,
config.fft_size * sample_rate // config.internal_sample_rate,
name,
Code.ERROR_TARGET_LENGTH_IS_EXCEEDED
if name == "TARGET"
else Code.ERROR_REFERENCE_LENGTH_LENGTH_IS_EXCEEDED,
Code.ERROR_TARGET_LENGTH_IS_TOO_SMALL
if name == "TARGET"
else Code.ERROR_REFERENCE_LENGTH_LENGTH_TOO_SMALL,
)
array = __check_channels(
array,
Code.INFO_TARGET_IS_MONO if name == "TARGET" else Code.INFO_REFERENCE_IS_MONO,
Code.ERROR_TARGET_NUM_OF_CHANNELS_IS_EXCEEDED
if name == "TARGET"
else Code.ERROR_REFERENCE_NUM_OF_CHANNELS_IS_EXCEEDED,
)
array, sample_rate = __check_sample_rate(
array,
sample_rate,
config.internal_sample_rate,
name,
warning if name == "TARGET" else info,
Code.WARNING_TARGET_IS_RESAMPLED
if name == "TARGET"
else Code.INFO_REFERENCE_IS_RESAMPLED,
)
if name == "TARGET":
__check_clipping_limiting(
array,
config.clipping_samples_threshold,
config.limited_samples_threshold,
Code.WARNING_TARGET_IS_CLIPPING,
Code.WARNING_TARGET_LIMITER_IS_APPLIED,
)
return array, sample_rate
def check_equality(target: np.ndarray, reference: np.ndarray) -> None:
if target.shape == reference.shape and np.allclose(target, reference):
raise ModuleError(Code.ERROR_TARGET_EQUALS_REFERENCE)