Spaces:
Runtime error
Runtime error
| import numpy as np | |
| from . import main | |
| def open_audio(path:str = None, lib:str = 'auto', normalize = True) -> tuple: | |
| """Opens audio from path, returns (audio, samplerate) tuple. | |
| Audio is returned as an array with normal volume range between -1, 1. | |
| Example of returned audio: | |
| [ | |
| [0.35, -0.25, ... -0.15, -0.15], | |
| [0.31, -0.21, ... -0.11, -0.07] | |
| ]""" | |
| if path is None: | |
| from tkinter.filedialog import askopenfilename | |
| path = askopenfilename(title='select song', filetypes=[("mp3", ".mp3"),("wav", ".wav"),("flac", ".flac"),("ogg", ".ogg"),("wma", ".wma")]) | |
| path=path.replace('\\', '/') | |
| if lib=='pedalboard.io': | |
| import pedalboard.io | |
| with pedalboard.io.AudioFile(path) as f: | |
| audio = f.read(f.frames) | |
| sr = f.samplerate | |
| elif lib=='librosa': | |
| import librosa | |
| audio, sr = librosa.load(path, sr=None, mono=False) | |
| elif lib=='soundfile': | |
| import soundfile | |
| audio, sr = soundfile.read(path) | |
| audio=audio.T | |
| elif lib=='madmom': | |
| import madmom | |
| audio, sr = madmom.io.audio.load_audio_file(path, dtype=float) | |
| audio=audio.T | |
| # elif lib=='pydub': | |
| # from pydub import AudioSegment | |
| # song=AudioSegment.from_file(filename) | |
| # audio = song.get_array_of_samples() | |
| # samplerate=song.frame_rate | |
| # print(audio) | |
| # print(filename) | |
| elif lib=='auto': | |
| for i in ('madmom', 'soundfile', 'librosa', 'pedalboard.io'): | |
| try: | |
| audio,sr=open_audio(path, i) | |
| break | |
| except Exception as e: | |
| print(f'open_audio with {i}: {e}') | |
| if len(audio)>16: audio=np.array([audio, audio], copy=False) | |
| if normalize is True: | |
| audio = np.clip(audio, -1, 1) | |
| audio = audio*(1/np.max(np.abs(audio))) | |
| return audio.astype(np.float32),sr | |
| def _sr(sr): | |
| try: return int(sr) | |
| except (ValueError, TypeError): assert False, f"Audio is an array, but `sr` argument is not valid. If audio is an array, you have to provide samplerate as an integer in the `sr` argument. Currently sr = {sr} of type {type(sr)}" | |
| def write_audio(audio:np.ndarray, sr:int, output:str, lib:str='auto', libs=('pedalboard.io', 'soundfile'), log = True): | |
| """"writes audio to path specified by output. Path should end with file extension, for example `folder/audio.mp3`""" | |
| if log is True: print(f'Writing {output}...', end=' ') | |
| assert _iterable(audio), f"audio should be an array/iterable object, but it is {type(audio)}" | |
| sr = _sr(sr) | |
| if not isinstance(audio, np.ndarray): audio = np.array(audio, copy=False) | |
| if lib=='pedalboard.io': | |
| #print(audio) | |
| import pedalboard.io | |
| with pedalboard.io.AudioFile(output, 'w', sr, audio.shape[0]) as f: | |
| f.write(audio) | |
| elif lib=='soundfile': | |
| audio=audio.T | |
| import soundfile | |
| soundfile.write(output, audio, sr) | |
| del audio | |
| elif lib=='auto': | |
| for i in libs: | |
| try: | |
| write_audio(audio=audio, sr=sr, output=output, lib=i, log = False) | |
| break | |
| except Exception as e: | |
| print(e) | |
| else: assert False, 'Failed to write audio, chances are there is something wrong with it...' | |
| if log is True: print(f'Done!') | |
| def _iterable(a): | |
| try: | |
| _ = iter(a) | |
| return True | |
| except TypeError: return False | |
| def _load(audio, sr:int = None, lib:str = 'auto', channels:int = 2, transpose3D:bool = False) -> tuple: | |
| """Automatically converts audio from path or any format to [[...],[...]] array. Returns (audio, samplerate) tuple.""" | |
| # path | |
| if isinstance(audio, str): return(open_audio(path=audio, lib=lib)) | |
| # array | |
| if _iterable(audio): | |
| if isinstance(audio, main.song): | |
| if sr is None: sr = audio.sr | |
| audio = audio.audio | |
| # sr is provided in a tuple | |
| if sr is None and len(audio) == 2: | |
| if not _iterable(audio[0]): | |
| sr = audio[0] | |
| audio = audio[1] | |
| elif not _iterable(audio[1]): | |
| sr = audio[1] | |
| audio = audio[0] | |
| if not isinstance(audio, np.ndarray): audio = np.array(audio, copy=False) | |
| sr = _sr(sr) | |
| if _iterable(audio[0]): | |
| # image | |
| if _iterable(audio[0][0]): | |
| audio2 = [] | |
| if transpose3D is True: audio = audio.T | |
| for i in audio: | |
| audio2.extend(_load(audio=i, sr=sr, lib=lib, channels=channels, transpose3D=transpose3D)[0]) | |
| return audio2, sr | |
| # transposed | |
| if len(audio) > 16: | |
| audio = audio.T | |
| return _load(audio=audio, sr=sr, lib=lib, channels=channels, transpose3D=transpose3D) | |
| # multi channel | |
| elif isinstance(channels, int): | |
| if len(audio) >= channels: | |
| return audio[:channels], sr | |
| # masked mono | |
| else: return np.array([audio[0] for _ in range(channels)], copy=False), sr | |
| else: return audio, sr | |
| else: | |
| # mono | |
| return (np.array([audio for _ in range(channels)], copy=False) if channels is not None else audio), sr | |
| # unknown | |
| else: assert False, f"Audio should be either a string with path, an array/iterable object, or a song object, but it is {type(audio)}" | |
| def _tosong(audio, sr=None): | |
| if isinstance(audio, main.song): return audio | |
| else: | |
| audio, sr = _load(audio = audio, sr = sr) | |
| return main.song(audio=audio, sr = sr) | |
| def _outputfilename(path:str = None, filename:str = None, suffix:str = None, ext:str = None): | |
| """If path has file extension, returns `path + suffix + ext`. Else returns `path + filename + suffix + .ext`. If nothing is specified, returns `output.mp3`""" | |
| if ext is not None: | |
| if not ext.startswith('.'): ext = '.'+ext | |
| if path is None: path = '' | |
| if path.endswith('/') or path.endswith('\\'): path=path[:-1] | |
| if '.' in path: | |
| path = path.split('.') | |
| if path[-1].lower() in ['mp3', 'wav', 'flac', 'ogg', 'wma', 'aac', 'ac3', 'aiff']: | |
| if ext is not None: | |
| path[-1] = ext | |
| if suffix is not None: path[len(path)-2]+=suffix | |
| return ''.join(path) | |
| else: path = ''.join(path) | |
| if filename is not None: | |
| filename = filename.replace('\\','/').split('/')[-1] | |
| if '.' in filename: | |
| filename = filename.split('.') | |
| if filename[-1].lower() in ['mp3', 'wav', 'flac', 'ogg', 'wma', 'aac', 'ac3', 'aiff']: | |
| if ext is not None: | |
| filename[-1] = ext | |
| if suffix is not None: filename.insert(len(filename)-1, suffix) | |
| else: filename += [ext] | |
| filename = ''.join(filename) | |
| return f'{path}/{filename}' if path != '' else filename | |
| return f'{(path + "/") * (path != "")}{filename}{suffix if suffix is not None else ""}.{ext if ext is not None else "mp3"}' | |
| else: return f'{path}/output.mp3' | |