Coverage for src\simplestretch\__init__.py: 100%

29 statements  

« prev     ^ index     » next       coverage.py v7.5.3, created at 2024-06-08 17:18 +0100

1from typing import Optional, Tuple, Union 

2 

3import soundfile 

4from numpy import ndarray 

5import pathlib 

6 

7 

8def stretch_audio( 

9 audio: Union[str, ndarray], 

10 factor: float, 

11 output: Optional[str] = None, 

12 samplerate: Optional[int] = None, 

13) -> Tuple[ndarray, int]: 

14 """This function is used to stretch an audio's length by a certain factor.\n 

15 Because this function doesn't apply any resampling or similar algorithms, for very high factors (around 5 or higher) the audio quality might decrease noticeably. 

16 

17 :param audio: The audio to be stretched.\n 

18 You can provide either a path to a file containing your audio, or the raw sound data as a numpy ndarray. 

19 :type audio: str | numpy.ndarray 

20 

21 :param factor: This is the factor by which the length of the audio will be changed.\n 

22 For example, a factor of 2 will make the audio twice as long, and a factor of 0.5 will make the audio half as long. 

23 :type factor: float 

24 

25 :param output: This is the path to which the stretched audio will be saved.\n 

26 If no argument is passed, it wont save the audio to a file. 

27 :type output: str, optional 

28 

29 :param samplerate: The sample rate of the original audio.\n 

30 You only need to pass this argument if you've provided a numpy ndarray as the audio. Otherwise, it will be determined automatically. 

31 :type samplerate: int, optional 

32 

33 :return: A tuple containing the stretched audio data and sample rate.\n 

34 This is returned whether or not the audio gets saved to a file. 

35 :rtype: Tuple[ndarray, int] 

36 

37 """ 

38 

39 # Type checks 

40 if not (isinstance(audio, str) or isinstance(audio, ndarray)): 

41 raise TypeError("'audio' must be the path to a audio file or a numpy ndarray") 

42 

43 if factor <= 0: 

44 raise ValueError("'factor' must be greater than 0") 

45 

46 if isinstance(audio, ndarray) and not isinstance(samplerate, int): 

47 try: 

48 samplerate = int(samplerate) 

49 except: 

50 raise TypeError(f"You must provide a valid sample rate when working with raw audio data (Not {type(samplerate)})") 

51 

52 

53 # If a file path is provided, load it as a ndarray using soundfile 

54 if isinstance(audio, str): 

55 audio, samplerate = soundfile.read(audio) 

56 

57 stretched_samplerate = round(samplerate / factor) 

58 

59 if isinstance(output, str): 

60 try: 

61 soundfile.write(output, audio, samplerate=stretched_samplerate) 

62 except soundfile.LibsndfileError as exc: 

63 # Delete invalid file 

64 pathlib.Path(output).unlink() 

65 

66 exc.add_note("(Try saving it as a .wav file instead)") 

67 raise exc 

68 

69 return (audio, stretched_samplerate) 

70 

71 

72def speedup_audio( 

73 audio: Union[str, ndarray], 

74 factor: float, 

75 output: Optional[str] = None, 

76 samplerate: Optional[int] = None, 

77) -> Tuple[ndarray, int]: 

78 """This function is used to change an audio's speed by a certain factor.\n 

79 Because this function doesn't apply any resampling or similar algorithms, for very low factors (around 0.2 or lower) the audio quality might decrease noticeably. 

80 

81 :param audio: The audio to be sped up or down.\n 

82 You can provide either a path to a file containing your audio, or the raw sound data as a numpy ndarray. 

83 :type audio: str | numpy.ndarray 

84 

85 :param factor: This is the factor by which the speed of the audio will be changed.\n 

86 For example, a factor of 2 will make the audio twice as fast, and a factor of 0.5 will make the audio half as fast. 

87 :type factor: float 

88 

89 :param output: This is the path to which the sped up audio will be saved.\n 

90 If no argument is passed, it wont save the audio to a file. 

91 :type output: str, optional 

92 

93 :param samplerate: The sample rate of the original audio.\n 

94 You only need to pass this argument if you've provided a numpy ndarray as the audio. Otherwise, it will be determined automatically. 

95 :type samplerate: int, optional 

96 

97 :return: A tuple containing the sped up audio data and sample rate.\n 

98 This is returned whether or not the audio gets saved to a file. 

99 :rtype: Tuple[ndarray, int] 

100 

101 """ 

102 

103 # Type checks 

104 if factor <= 0: 

105 raise ValueError("'factor' must be greater than 0") 

106 

107 # Stretch audio to match the specified speedup factor 

108 return stretch_audio( 

109 audio=audio, factor=1 / factor, output=output, samplerate=samplerate 

110 )