Skip to content

Commit 7bb3058

Browse files
committed
added skip and custom timeshift options
1 parent 08bf8e7 commit 7bb3058

File tree

2 files changed

+38
-18
lines changed

2 files changed

+38
-18
lines changed

pitcher.py

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@
1111
import scipy as sp
1212
import audiofile as af
1313

14+
from pydub import AudioSegment
1415
from librosa import load
1516
from librosa.core import resample
16-
from pydub import AudioSegment
17+
from librosa.effects import time_stretch
1718

1819
ZOH_MULTIPLIER = 4
1920
RESAMPLE_MULTIPLIER = 2
@@ -51,24 +52,29 @@ def calc_quantize_function(quantize_bits, log):
5152
return s_midrise, s_midtread
5253

5354

54-
def adjust_pitch(x, st, log):
55+
def adjust_pitch(x, st, skip_time_stretch, log):
5556
log.info(f'adjusting audio pitch by {st} semitones')
57+
t = 0
5658
if (0 > st >= -8):
5759
t = NEGATIVE_TUNING_RATIOS[st]
5860
elif st > 0:
5961
t = POSITIVE_TUNING_RATIO ** -st
6062
elif st == 0: # no change
6163
return x
6264
else: # -8 > st: extrapolate, seems to lose a few points of precision?
63-
f = sp.interpolate.interp1d(list(NEGATIVE_TUNING_RATIOS.keys()),
64-
list(NEGATIVE_TUNING_RATIOS.values()),
65-
fill_value='extrapolate')
65+
f = sp.interpolate.interp1d(
66+
list(NEGATIVE_TUNING_RATIOS.keys()),
67+
list(NEGATIVE_TUNING_RATIOS.values()),
68+
fill_value='extrapolate'
69+
)
6670
t = f(st)
6771

6872
n = int(np.round(len(x) * t))
6973
r = np.linspace(0, len(x) - 1, n).round().astype(np.int32)
70-
pitched = [x[r[e]] for e in range(n-1)] # could yield here instead
74+
pitched = [x[r[e]] for e in range(n-1)] # could yield instead
75+
pitched = np.array(pitched)
7176
log.info('done pitching audio')
77+
7278
return pitched
7379

7480

@@ -160,8 +166,11 @@ def write_mp3(f, x, sr, normalized=False):
160166
@click.option('--skip-normalize', is_flag=True, default=False)
161167
@click.option('--skip-input-filter', is_flag=True, default=False)
162168
@click.option('--skip-output-filter', is_flag=True, default=False)
169+
@click.option('--skip-time-stretch', is_flag=True, default=False)
170+
@click.option('--custom-time-stretch', default=0, type=float)
163171
def pitch(st, log_level, input_file, output_file, quantize_bits, skip_normalize,
164-
skip_quantize, skip_input_filter, skip_output_filter):
172+
skip_quantize, skip_input_filter, skip_output_filter, skip_time_stretch,
173+
custom_time_stretch):
165174

166175
log = logging.getLogger(__name__)
167176
sh = logging.StreamHandler()
@@ -197,7 +206,17 @@ def pitch(st, log_level, input_file, output_file, quantize_bits, skip_normalize,
197206
# TODO: midtread/midrise option?
198207
resampled = quantize(resampled, midtread, quantize_bits, log)
199208

200-
pitched = adjust_pitch(resampled, st, log)
209+
210+
pitched = adjust_pitch(resampled, st, skip_time_stretch, log)
211+
212+
if skip_time_stretch:
213+
ratio = len(pitched) / len(resampled)
214+
log.info('\"skipping\" time stretch: stretching back to original length...')
215+
pitched = time_stretch(pitched, ratio)
216+
217+
if custom_time_stretch:
218+
log.info('running custom time stretch of ratio: {custom_time_stretch}')
219+
pitched = time_stretch(pitched, custom_time_stretch)
201220

202221
# oversample again (default factor of 4) to simulate ZOH
203222
# TODO: retest output against freq aliased sinc fn
@@ -218,6 +237,7 @@ def pitch(st, log_level, input_file, output_file, quantize_bits, skip_normalize,
218237
if '.mp3' in output_file:
219238
write_mp3(output_file, output, OUTPUT_SR, not skip_normalize)
220239
else:
240+
output_file = output_file
221241
af.write(output_file, output, OUTPUT_SR, '16bit', not skip_normalize)
222242

223243
log.info(f'done! output_file at: {output_file}')

readme.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,23 @@ python pitcher.py --input-file ./input.wav --st -4 --output-file ./output.wav
2121

2222
### Options:
2323
```
24-
--st - # semitones to shift pitch by, int, required
25-
--input-file - path to input file, string, required
26-
--output-file - path to output file, string, required
27-
--quantize-bits - bit rate of quantized output, int, default 12
28-
--skip-quantize - skip simulation of ADC quantize, flag
29-
--skip-normalize - skip output normalization, flag
30-
--skip-input-filter - skip input anti aliasing filter, flag
31-
--skip-output-filter - skip output equalization filter, flag
24+
--st - # semitones to shift pitch by, int, required
25+
--input-file - path to input file, string, required
26+
--output-file - path to output file, string, required
27+
--quantize-bits - bit rate of quantized output, int, default 12
28+
--time-shift - custom time shift ratio to apply, float, default 0
29+
--skip-quantize - skip simulation of ADC quantize, flag
30+
--skip-normalize - skip output normalization, flag
31+
--skip-input-filter - skip input anti aliasing filter, flag
32+
--skip-output-filter - skip output equalization filter, flag
33+
--skip-time-shift - skip time sfhit inherent to pitching algorithm, flag
3234
```
3335

3436
If you find this project useful, please consider donating to the [NAACP Legal Defense Fund](https://org2.salsalabs.com/o/6857/p/salsa/donation/common/public/?donate_page_KEY=15780&_ga=2.209233111.496632409.1590767838-1184367471.1590767838) or [BLM - TO](https://blacklivesmatter.ca/donate/)
3537

3638

3739
### TODO:
38-
- append wav if no file type, breaks audiofile save
3940
- optionally preserve stereo channels throughout processing
4041
- optional vcf (moog ring) good description in slides
41-
- time_shift/no time_shift option
4242
- replace librosa if there is a module with better performance, maybe essentia?
4343
- improve high end input anti aliasing filter fit?

0 commit comments

Comments
 (0)