1010import lameenc
1111import julius
1212import numpy as np
13- from . import audio_legacy
13+ from . import audio_legacy # noqa: F401
1414import torch
1515import torchaudio as ta
1616import typing as tp
1919
2020
2121def _read_info (path ):
22- stdout_data = sp .check_output ([
23- 'ffprobe' , "-loglevel" , "panic" ,
24- str (path ), '-print_format' , 'json' , '-show_format' , '-show_streams'
25- ])
26- return json .loads (stdout_data .decode ('utf-8' ))
22+ stdout_data = sp .check_output (
23+ [
24+ "ffprobe" ,
25+ "-loglevel" ,
26+ "panic" ,
27+ str (path ),
28+ "-print_format" ,
29+ "json" ,
30+ "-show_format" ,
31+ "-show_streams" ,
32+ ]
33+ )
34+ return json .loads (stdout_data .decode ("utf-8" ))
2735
2836
2937class AudioFile :
3038 """
3139 Allows to read audio from any format supported by ffmpeg, as well as resampling or
3240 converting to mono on the fly. See :method:`read` for more details.
3341 """
42+
3443 def __init__ (self , path : Path ):
3544 self .path = Path (path )
3645 self ._info = None
@@ -51,30 +60,33 @@ def info(self):
5160
5261 @property
5362 def duration (self ):
54- return float (self .info [' format' ][ ' duration' ])
63+ return float (self .info [" format" ][ " duration" ])
5564
5665 @property
5766 def _audio_streams (self ):
5867 return [
59- index for index , stream in enumerate (self .info ["streams" ])
68+ index
69+ for index , stream in enumerate (self .info ["streams" ])
6070 if stream ["codec_type" ] == "audio"
6171 ]
6272
6373 def __len__ (self ):
6474 return len (self ._audio_streams )
6575
6676 def channels (self , stream = 0 ):
67- return int (self .info [' streams' ][self ._audio_streams [stream ]][' channels' ])
77+ return int (self .info [" streams" ][self ._audio_streams [stream ]][" channels" ])
6878
6979 def samplerate (self , stream = 0 ):
70- return int (self .info ['streams' ][self ._audio_streams [stream ]]['sample_rate' ])
71-
72- def read (self ,
73- seek_time = None ,
74- duration = None ,
75- streams = slice (None ),
76- samplerate = None ,
77- channels = None ):
80+ return int (self .info ["streams" ][self ._audio_streams [stream ]]["sample_rate" ])
81+
82+ def read (
83+ self ,
84+ seek_time = None ,
85+ duration = None ,
86+ streams = slice (None ),
87+ samplerate = None ,
88+ channels = None ,
89+ ):
7890 """
7991 Slightly more efficient implementation than stempeg,
8092 in particular, this will extract all stems at once
@@ -106,22 +118,24 @@ def read(self,
106118 query_duration = None
107119 else :
108120 target_size = int ((samplerate or self .samplerate ()) * duration )
109- query_duration = float ((target_size + 1 ) / (samplerate or self .samplerate ()))
121+ query_duration = float (
122+ (target_size + 1 ) / (samplerate or self .samplerate ())
123+ )
110124
111125 with temp_filenames (len (streams )) as filenames :
112- command = [' ffmpeg' , '-y' ]
113- command += [' -loglevel' , ' panic' ]
126+ command = [" ffmpeg" , "-y" ]
127+ command += [" -loglevel" , " panic" ]
114128 if seek_time :
115- command += [' -ss' , str (seek_time )]
116- command += ['-i' , str (self .path )]
129+ command += [" -ss" , str (seek_time )]
130+ command += ["-i" , str (self .path )]
117131 for stream , filename in zip (streams , filenames ):
118- command += [' -map' , f' 0:{ self ._audio_streams [stream ]} ' ]
132+ command += [" -map" , f" 0:{ self ._audio_streams [stream ]} " ]
119133 if query_duration is not None :
120- command += ['-t' , str (query_duration )]
121- command += [' -threads' , '1' ]
122- command += ['-f' , ' f32le' ]
134+ command += ["-t" , str (query_duration )]
135+ command += [" -threads" , "1" ]
136+ command += ["-f" , " f32le" ]
123137 if samplerate is not None :
124- command += [' -ar' , str (samplerate )]
138+ command += [" -ar" , str (samplerate )]
125139 command += [filename ]
126140
127141 sp .run (command , check = True )
@@ -163,7 +177,9 @@ def convert_audio_channels(wav, channels=2):
163177 wav = wav [..., :channels , :]
164178 else :
165179 # Case 4: What is a reasonable choice here?
166- raise ValueError ('The audio file has less channels than requested but is not mono.' )
180+ raise ValueError (
181+ "The audio file has less channels than requested but is not mono."
182+ )
167183 return wav
168184
169185
@@ -216,32 +232,34 @@ def encode_mp3(wav, path, samplerate=44100, bitrate=320, quality=2, verbose=Fals
216232 f .write (mp3_data )
217233
218234
219- def prevent_clip (wav , mode = ' rescale' ):
235+ def prevent_clip (wav , mode = " rescale" ):
220236 """
221237 different strategies for avoiding raw clipping.
222238 """
223- if mode is None or mode == ' none' :
239+ if mode is None or mode == " none" :
224240 return wav
225241 assert wav .dtype .is_floating_point , "too late for clipping"
226- if mode == ' rescale' :
242+ if mode == " rescale" :
227243 wav = wav / max (1.01 * wav .abs ().max (), 1 )
228- elif mode == ' clamp' :
244+ elif mode == " clamp" :
229245 wav = wav .clamp (- 0.99 , 0.99 )
230- elif mode == ' tanh' :
246+ elif mode == " tanh" :
231247 wav = torch .tanh (wav )
232248 else :
233249 raise ValueError (f"Invalid mode { mode } " )
234250 return wav
235251
236252
237- def save_audio (wav : torch .Tensor ,
238- path : tp .Union [str , Path ],
239- samplerate : int ,
240- bitrate : int = 320 ,
241- clip : tp .Literal ["rescale" , "clamp" , "tanh" , "none" ] = 'rescale' ,
242- bits_per_sample : tp .Literal [16 , 24 , 32 ] = 16 ,
243- as_float : bool = False ,
244- preset : tp .Literal [2 , 3 , 4 , 5 , 6 , 7 ] = 2 ):
253+ def save_audio (
254+ wav : torch .Tensor ,
255+ path : tp .Union [str , Path ],
256+ samplerate : int ,
257+ bitrate : int = 320 ,
258+ clip : tp .Literal ["rescale" , "clamp" , "tanh" , "none" ] = "rescale" ,
259+ bits_per_sample : tp .Literal [16 , 24 , 32 ] = 16 ,
260+ as_float : bool = False ,
261+ preset : tp .Literal [2 , 3 , 4 , 5 , 6 , 7 ] = 2 ,
262+ ):
245263 """Save audio file, automatically preventing clipping if necessary
246264 based on the given `clip` strategy. If the path ends in `.mp3`, this
247265 will save as mp3 with the given `bitrate`. Use `preset` to set mp3 quality:
@@ -255,11 +273,16 @@ def save_audio(wav: torch.Tensor,
255273 elif suffix == ".wav" :
256274 if as_float :
257275 bits_per_sample = 32
258- encoding = ' PCM_F'
276+ encoding = " PCM_F"
259277 else :
260- encoding = 'PCM_S'
261- ta .save (str (path ), wav , sample_rate = samplerate ,
262- encoding = encoding , bits_per_sample = bits_per_sample )
278+ encoding = "PCM_S"
279+ ta .save (
280+ str (path ),
281+ wav ,
282+ sample_rate = samplerate ,
283+ encoding = encoding ,
284+ bits_per_sample = bits_per_sample ,
285+ )
263286 elif suffix == ".flac" :
264287 ta .save (str (path ), wav , sample_rate = samplerate , bits_per_sample = bits_per_sample )
265288 else :
0 commit comments