/
time_frequency.py
1929 lines (1453 loc) · 53.9 KB
/
time_frequency.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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''Time and frequency utilities'''
import re
import numpy as np
from .._cache import cache
from ..util.exceptions import ParameterError
__all__ = ['frames_to_samples', 'frames_to_time',
'samples_to_frames', 'samples_to_time',
'time_to_samples', 'time_to_frames',
'blocks_to_samples', 'blocks_to_frames',
'blocks_to_time',
'note_to_hz', 'note_to_midi',
'midi_to_hz', 'midi_to_note',
'hz_to_note', 'hz_to_midi',
'hz_to_mel', 'hz_to_octs',
'mel_to_hz',
'octs_to_hz',
'A4_to_tuning',
'tuning_to_A4',
'fft_frequencies',
'cqt_frequencies',
'mel_frequencies',
'tempo_frequencies',
'fourier_tempo_frequencies',
'A_weighting',
'B_weighting',
'C_weighting',
'D_weighting',
'Z_weighting',
'frequency_weighting',
'multi_frequency_weighting',
'samples_like',
'times_like',
'key_to_notes',
'key_to_degrees']
def frames_to_samples(frames, hop_length=512, n_fft=None):
"""Converts frame indices to audio sample indices.
Parameters
----------
frames : number or np.ndarray [shape=(n,)]
frame index or vector of frame indices
hop_length : int > 0 [scalar]
number of samples between successive frames
n_fft : None or int > 0 [scalar]
Optional: length of the FFT window.
If given, time conversion will include an offset of `n_fft / 2`
to counteract windowing effects when using a non-centered STFT.
Returns
-------
times : number or np.ndarray
time (in samples) of each given frame number:
`times[i] = frames[i] * hop_length`
See Also
--------
frames_to_time : convert frame indices to time values
samples_to_frames : convert sample indices to frame indices
Examples
--------
>>> y, sr = librosa.load(librosa.util.example_audio_file())
>>> tempo, beats = librosa.beat.beat_track(y, sr=sr)
>>> beat_samples = librosa.frames_to_samples(beats)
"""
offset = 0
if n_fft is not None:
offset = int(n_fft // 2)
return (np.asanyarray(frames) * hop_length + offset).astype(int)
def samples_to_frames(samples, hop_length=512, n_fft=None):
"""Converts sample indices into STFT frames.
Examples
--------
>>> # Get the frame numbers for every 256 samples
>>> librosa.samples_to_frames(np.arange(0, 22050, 256))
array([ 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13,
14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20,
21, 21, 22, 22, 23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
28, 28, 29, 29, 30, 30, 31, 31, 32, 32, 33, 33, 34, 34,
35, 35, 36, 36, 37, 37, 38, 38, 39, 39, 40, 40, 41, 41,
42, 42, 43])
Parameters
----------
samples : int or np.ndarray [shape=(n,)]
sample index or vector of sample indices
hop_length : int > 0 [scalar]
number of samples between successive frames
n_fft : None or int > 0 [scalar]
Optional: length of the FFT window.
If given, time conversion will include an offset of `- n_fft / 2`
to counteract windowing effects in STFT.
.. note:: This may result in negative frame indices.
Returns
-------
frames : int or np.ndarray [shape=(n,), dtype=int]
Frame numbers corresponding to the given times:
`frames[i] = floor( samples[i] / hop_length )`
See Also
--------
samples_to_time : convert sample indices to time values
frames_to_samples : convert frame indices to sample indices
"""
offset = 0
if n_fft is not None:
offset = int(n_fft // 2)
samples = np.asanyarray(samples)
return np.floor((samples - offset) // hop_length).astype(int)
def frames_to_time(frames, sr=22050, hop_length=512, n_fft=None):
"""Converts frame counts to time (seconds).
Parameters
----------
frames : np.ndarray [shape=(n,)]
frame index or vector of frame indices
sr : number > 0 [scalar]
audio sampling rate
hop_length : int > 0 [scalar]
number of samples between successive frames
n_fft : None or int > 0 [scalar]
Optional: length of the FFT window.
If given, time conversion will include an offset of `n_fft / 2`
to counteract windowing effects when using a non-centered STFT.
Returns
-------
times : np.ndarray [shape=(n,)]
time (in seconds) of each given frame number:
`times[i] = frames[i] * hop_length / sr`
See Also
--------
time_to_frames : convert time values to frame indices
frames_to_samples : convert frame indices to sample indices
Examples
--------
>>> y, sr = librosa.load(librosa.util.example_audio_file())
>>> tempo, beats = librosa.beat.beat_track(y, sr=sr)
>>> beat_times = librosa.frames_to_time(beats, sr=sr)
"""
samples = frames_to_samples(frames,
hop_length=hop_length,
n_fft=n_fft)
return samples_to_time(samples, sr=sr)
def time_to_frames(times, sr=22050, hop_length=512, n_fft=None):
"""Converts time stamps into STFT frames.
Parameters
----------
times : np.ndarray [shape=(n,)]
time (in seconds) or vector of time values
sr : number > 0 [scalar]
audio sampling rate
hop_length : int > 0 [scalar]
number of samples between successive frames
n_fft : None or int > 0 [scalar]
Optional: length of the FFT window.
If given, time conversion will include an offset of `- n_fft / 2`
to counteract windowing effects in STFT.
.. note:: This may result in negative frame indices.
Returns
-------
frames : np.ndarray [shape=(n,), dtype=int]
Frame numbers corresponding to the given times:
`frames[i] = floor( times[i] * sr / hop_length )`
See Also
--------
frames_to_time : convert frame indices to time values
time_to_samples : convert time values to sample indices
Examples
--------
Get the frame numbers for every 100ms
>>> librosa.time_to_frames(np.arange(0, 1, 0.1),
... sr=22050, hop_length=512)
array([ 0, 4, 8, 12, 17, 21, 25, 30, 34, 38])
"""
samples = time_to_samples(times, sr=sr)
return samples_to_frames(samples, hop_length=hop_length, n_fft=n_fft)
def time_to_samples(times, sr=22050):
'''Convert timestamps (in seconds) to sample indices.
Parameters
----------
times : number or np.ndarray
Time value or array of time values (in seconds)
sr : number > 0
Sampling rate
Returns
-------
samples : int or np.ndarray [shape=times.shape, dtype=int]
Sample indices corresponding to values in `times`
See Also
--------
time_to_frames : convert time values to frame indices
samples_to_time : convert sample indices to time values
Examples
--------
>>> librosa.time_to_samples(np.arange(0, 1, 0.1), sr=22050)
array([ 0, 2205, 4410, 6615, 8820, 11025, 13230, 15435,
17640, 19845])
'''
return (np.asanyarray(times) * sr).astype(int)
def samples_to_time(samples, sr=22050):
'''Convert sample indices to time (in seconds).
Parameters
----------
samples : np.ndarray
Sample index or array of sample indices
sr : number > 0
Sampling rate
Returns
-------
times : np.ndarray [shape=samples.shape]
Time values corresponding to `samples` (in seconds)
See Also
--------
samples_to_frames : convert sample indices to frame indices
time_to_samples : convert time values to sample indices
Examples
--------
Get timestamps corresponding to every 512 samples
>>> librosa.samples_to_time(np.arange(0, 22050, 512))
array([ 0. , 0.023, 0.046, 0.07 , 0.093, 0.116, 0.139,
0.163, 0.186, 0.209, 0.232, 0.255, 0.279, 0.302,
0.325, 0.348, 0.372, 0.395, 0.418, 0.441, 0.464,
0.488, 0.511, 0.534, 0.557, 0.58 , 0.604, 0.627,
0.65 , 0.673, 0.697, 0.72 , 0.743, 0.766, 0.789,
0.813, 0.836, 0.859, 0.882, 0.906, 0.929, 0.952,
0.975, 0.998])
'''
return np.asanyarray(samples) / float(sr)
def blocks_to_frames(blocks, block_length):
'''Convert block indices to frame indices
Parameters
----------
blocks : np.ndarray
Block index or array of block indices
block_length : int > 0
The number of frames per block
Returns
-------
frames : np.ndarray [shape=samples.shape, dtype=int]
The index or indices of frames corresponding to the beginning
of each provided block.
See Also
--------
blocks_to_samples
blocks_to_time
Examples
--------
Get frame indices for each block in a stream
>>> filename = librosa.util.example_audio_file()
>>> sr = librosa.get_samplerate(filename)
>>> stream = librosa.stream(filename, block_length=16,
... frame_length=2048, hop_length=512)
>>> for n, y in enumerate(stream):
... n_frame = librosa.blocks_to_frames(n, block_length=16)
'''
return block_length * np.asanyarray(blocks)
def blocks_to_samples(blocks, block_length, hop_length):
'''Convert block indices to sample indices
Parameters
----------
blocks : np.ndarray
Block index or array of block indices
block_length : int > 0
The number of frames per block
hop_length : int > 0
The number of samples to advance between frames
Returns
-------
samples : np.ndarray [shape=samples.shape, dtype=int]
The index or indices of samples corresponding to the beginning
of each provided block.
Note that these correspond to the *first* sample index in
each block, and are not frame-centered.
See Also
--------
blocks_to_frames
blocks_to_time
Examples
--------
Get sample indices for each block in a stream
>>> filename = librosa.util.example_audio_file()
>>> sr = librosa.get_samplerate(filename)
>>> stream = librosa.stream(filename, block_length=16,
... frame_length=2048, hop_length=512)
>>> for n, y in enumerate(stream):
... n_sample = librosa.blocks_to_samples(n, block_length=16,
... hop_length=512)
'''
frames = blocks_to_frames(blocks, block_length)
return frames_to_samples(frames, hop_length=hop_length)
def blocks_to_time(blocks, block_length, hop_length, sr):
'''Convert block indices to time (in seconds)
Parameters
----------
blocks : np.ndarray
Block index or array of block indices
block_length : int > 0
The number of frames per block
hop_length : int > 0
The number of samples to advance between frames
sr : int > 0
The sampling rate (samples per second)
Returns
-------
times : np.ndarray [shape=samples.shape]
The time index or indices (in seconds) corresponding to the
beginning of each provided block.
Note that these correspond to the time of the *first* sample
in each block, and are not frame-centered.
See Also
--------
blocks_to_frames
blocks_to_samples
Examples
--------
Get time indices for each block in a stream
>>> filename = librosa.util.example_audio_file()
>>> sr = librosa.get_samplerate(filename)
>>> stream = librosa.stream(filename, block_length=16,
... frame_length=2048, hop_length=512)
>>> for n, y in enumerate(stream):
... n_time = librosa.blocks_to_time(n, block_length=16,
... hop_length=512, sr=sr)
'''
samples = blocks_to_samples(blocks, block_length, hop_length)
return samples_to_time(samples, sr=sr)
def note_to_hz(note, **kwargs):
'''Convert one or more note names to frequency (Hz)
Examples
--------
>>> # Get the frequency of a note
>>> librosa.note_to_hz('C')
array([ 16.352])
>>> # Or multiple notes
>>> librosa.note_to_hz(['A3', 'A4', 'A5'])
array([ 220., 440., 880.])
>>> # Or notes with tuning deviations
>>> librosa.note_to_hz('C2-32', round_midi=False)
array([ 64.209])
Parameters
----------
note : str or iterable of str
One or more note names to convert
kwargs : additional keyword arguments
Additional parameters to `note_to_midi`
Returns
-------
frequencies : number or np.ndarray [shape=(len(note),)]
Array of frequencies (in Hz) corresponding to `note`
See Also
--------
midi_to_hz
note_to_midi
hz_to_note
'''
return midi_to_hz(note_to_midi(note, **kwargs))
def note_to_midi(note, round_midi=True):
'''Convert one or more spelled notes to MIDI number(s).
Notes may be spelled out with optional accidentals or octave numbers.
The leading note name is case-insensitive.
Sharps are indicated with ``#``, flats may be indicated with ``!`` or ``b``.
Parameters
----------
note : str or iterable of str
One or more note names.
round_midi : bool
- If `True`, allow for fractional midi notes
- Otherwise, round cent deviations to the nearest note
Returns
-------
midi : float or np.array
Midi note numbers corresponding to inputs.
Raises
------
ParameterError
If the input is not in valid note format
See Also
--------
midi_to_note
note_to_hz
Examples
--------
>>> librosa.note_to_midi('C')
12
>>> librosa.note_to_midi('C#3')
49
>>> librosa.note_to_midi('C♯3') # Using Unicode sharp
49
>>> librosa.note_to_midi('C♭3') # Using Unicode flat
47
>>> librosa.note_to_midi('f4')
65
>>> librosa.note_to_midi('Bb-1')
10
>>> librosa.note_to_midi('A!8')
116
>>> librosa.note_to_midi('G𝄪6') # Double-sharp
93
>>> librosa.note_to_midi('B𝄫6') # Double-flat
93
>>> librosa.note_to_midi('C♭𝄫5') # Triple-flats also work
69
>>> # Lists of notes also work
>>> librosa.note_to_midi(['C', 'E', 'G'])
array([12, 16, 19])
'''
if not isinstance(note, str):
return np.array([note_to_midi(n, round_midi=round_midi) for n in note])
pitch_map = {'C': 0, 'D': 2, 'E': 4, 'F': 5, 'G': 7, 'A': 9, 'B': 11}
acc_map = {'#': 1, '': 0, 'b': -1, '!': -1, '♯': 1, '𝄪': 2, '♭': -1, '𝄫': -2, '♮': 0}
match = re.match(r'^(?P<note>[A-Ga-g])'
r'(?P<accidental>[#♯𝄪b!♭𝄫♮]*)'
r'(?P<octave>[+-]?\d+)?'
r'(?P<cents>[+-]\d+)?$',
note)
if not match:
raise ParameterError('Improper note format: {:s}'.format(note))
pitch = match.group('note').upper()
offset = np.sum([acc_map[o] for o in match.group('accidental')])
octave = match.group('octave')
cents = match.group('cents')
if not octave:
octave = 0
else:
octave = int(octave)
if not cents:
cents = 0
else:
cents = int(cents) * 1e-2
note_value = 12 * (octave + 1) + pitch_map[pitch] + offset + cents
if round_midi:
note_value = int(np.round(note_value))
return note_value
def midi_to_note(midi, octave=True, cents=False, key='C:maj', unicode=True):
'''Convert one or more MIDI numbers to note strings.
MIDI numbers will be rounded to the nearest integer.
Notes will be of the format 'C0', 'C♯0', 'D0', ...
Examples
--------
>>> librosa.midi_to_note(0)
'C-1'
>>> librosa.midi_to_note(37)
'C♯2'
>>> librosa.midi_to_note(37, unicode=False)
'C#2'
>>> librosa.midi_to_note(-2)
'A♯-2'
>>> librosa.midi_to_note(104.7)
'A7'
>>> librosa.midi_to_note(104.7, cents=True)
'A7-30'
>>> librosa.midi_to_note(list(range(12, 24)))
['C0', 'C♯0', 'D0', 'D♯0', 'E0', 'F0', 'F♯0', 'G0', 'G♯0', 'A0', 'A♯0', 'B0']
Use a key signature to resolve enharmonic equivalences
>>> librosa.midi_to_note(range(12, 24), key='F:min')
['C0', 'D♭0', 'D0', 'E♭0', 'E0', 'F0', 'G♭0', 'G0', 'A♭0', 'A0', 'B♭0', 'B0']
Parameters
----------
midi : int or iterable of int
Midi numbers to convert.
octave: bool
If True, include the octave number
cents: bool
If true, cent markers will be appended for fractional notes.
Eg, `midi_to_note(69.3, cents=True)` == `A4+03`
key : str
A key signature to use when resolving enharmonic equivalences.
unicode: bool
If `True` (default), accidentals will use Unicode notation: ♭ or ♯
If `False`, accidentals will use ASCII-compatible notation: b or #
Returns
-------
notes : str or iterable of str
Strings describing each midi note.
Raises
------
ParameterError
if `cents` is True and `octave` is False
See Also
--------
midi_to_hz
note_to_midi
hz_to_note
key_to_notes
'''
if cents and not octave:
raise ParameterError('Cannot encode cents without octave information.')
if not np.isscalar(midi):
return [midi_to_note(x, octave=octave, cents=cents, key=key, unicode=unicode) for x in midi]
note_map = key_to_notes(key=key, unicode=unicode)
note_num = int(np.round(midi))
note_cents = int(100 * np.around(midi - note_num, 2))
note = note_map[note_num % 12]
if octave:
note = '{:s}{:0d}'.format(note, int(note_num / 12) - 1)
if cents:
note = '{:s}{:+02d}'.format(note, note_cents)
return note
def midi_to_hz(notes):
"""Get the frequency (Hz) of MIDI note(s)
Examples
--------
>>> librosa.midi_to_hz(36)
65.406
>>> librosa.midi_to_hz(np.arange(36, 48))
array([ 65.406, 69.296, 73.416, 77.782, 82.407,
87.307, 92.499, 97.999, 103.826, 110. ,
116.541, 123.471])
Parameters
----------
notes : int or np.ndarray [shape=(n,), dtype=int]
midi number(s) of the note(s)
Returns
-------
frequency : number or np.ndarray [shape=(n,), dtype=float]
frequency (frequencies) of `notes` in Hz
See Also
--------
hz_to_midi
note_to_hz
"""
return 440.0 * (2.0 ** ((np.asanyarray(notes) - 69.0)/12.0))
def hz_to_midi(frequencies):
"""Get MIDI note number(s) for given frequencies
Examples
--------
>>> librosa.hz_to_midi(60)
34.506
>>> librosa.hz_to_midi([110, 220, 440])
array([ 45., 57., 69.])
Parameters
----------
frequencies : float or np.ndarray [shape=(n,), dtype=float]
frequencies to convert
Returns
-------
note_nums : number or np.ndarray [shape=(n,), dtype=float]
MIDI notes to `frequencies`
See Also
--------
midi_to_hz
note_to_midi
hz_to_note
"""
return 12 * (np.log2(np.asanyarray(frequencies)) - np.log2(440.0)) + 69
def hz_to_note(frequencies, **kwargs):
'''Convert one or more frequencies (in Hz) to the nearest note names.
Parameters
----------
frequencies : float or iterable of float
Input frequencies, specified in Hz
kwargs : additional keyword arguments
Arguments passed through to `midi_to_note`
Returns
-------
notes : list of str
`notes[i]` is the closest note name to `frequency[i]`
(or `frequency` if the input is scalar)
See Also
--------
hz_to_midi
midi_to_note
note_to_hz
Examples
--------
Get a single note name for a frequency
>>> librosa.hz_to_note(440.0)
['A5']
Get multiple notes with cent deviation
>>> librosa.hz_to_note([32, 64], cents=True)
['C1-38', 'C2-38']
Get multiple notes, but suppress octave labels
>>> librosa.hz_to_note(440.0 * (2.0 ** np.linspace(0, 1, 12)),
... octave=False)
['A', 'A#', 'B', 'C', 'C#', 'D', 'E', 'F', 'F#', 'G', 'G#', 'A']
'''
return midi_to_note(hz_to_midi(frequencies), **kwargs)
def hz_to_mel(frequencies, htk=False):
"""Convert Hz to Mels
Examples
--------
>>> librosa.hz_to_mel(60)
0.9
>>> librosa.hz_to_mel([110, 220, 440])
array([ 1.65, 3.3 , 6.6 ])
Parameters
----------
frequencies : number or np.ndarray [shape=(n,)] , float
scalar or array of frequencies
htk : bool
use HTK formula instead of Slaney
Returns
-------
mels : number or np.ndarray [shape=(n,)]
input frequencies in Mels
See Also
--------
mel_to_hz
"""
frequencies = np.asanyarray(frequencies)
if htk:
return 2595.0 * np.log10(1.0 + frequencies / 700.0)
# Fill in the linear part
f_min = 0.0
f_sp = 200.0 / 3
mels = (frequencies - f_min) / f_sp
# Fill in the log-scale part
min_log_hz = 1000.0 # beginning of log region (Hz)
min_log_mel = (min_log_hz - f_min) / f_sp # same (Mels)
logstep = np.log(6.4) / 27.0 # step size for log region
if frequencies.ndim:
# If we have array data, vectorize
log_t = (frequencies >= min_log_hz)
mels[log_t] = min_log_mel + np.log(frequencies[log_t]/min_log_hz) / logstep
elif frequencies >= min_log_hz:
# If we have scalar data, heck directly
mels = min_log_mel + np.log(frequencies / min_log_hz) / logstep
return mels
def mel_to_hz(mels, htk=False):
"""Convert mel bin numbers to frequencies
Examples
--------
>>> librosa.mel_to_hz(3)
200.
>>> librosa.mel_to_hz([1,2,3,4,5])
array([ 66.667, 133.333, 200. , 266.667, 333.333])
Parameters
----------
mels : np.ndarray [shape=(n,)], float
mel bins to convert
htk : bool
use HTK formula instead of Slaney
Returns
-------
frequencies : np.ndarray [shape=(n,)]
input mels in Hz
See Also
--------
hz_to_mel
"""
mels = np.asanyarray(mels)
if htk:
return 700.0 * (10.0**(mels / 2595.0) - 1.0)
# Fill in the linear scale
f_min = 0.0
f_sp = 200.0 / 3
freqs = f_min + f_sp * mels
# And now the nonlinear scale
min_log_hz = 1000.0 # beginning of log region (Hz)
min_log_mel = (min_log_hz - f_min) / f_sp # same (Mels)
logstep = np.log(6.4) / 27.0 # step size for log region
if mels.ndim:
# If we have vector data, vectorize
log_t = (mels >= min_log_mel)
freqs[log_t] = min_log_hz * np.exp(logstep * (mels[log_t] - min_log_mel))
elif mels >= min_log_mel:
# If we have scalar data, check directly
freqs = min_log_hz * np.exp(logstep * (mels - min_log_mel))
return freqs
def hz_to_octs(frequencies, tuning=0.0, bins_per_octave=12):
"""Convert frequencies (Hz) to (fractional) octave numbers.
Examples
--------
>>> librosa.hz_to_octs(440.0)
4.
>>> librosa.hz_to_octs([32, 64, 128, 256])
array([ 0.219, 1.219, 2.219, 3.219])
Parameters
----------
frequencies : number >0 or np.ndarray [shape=(n,)] or float
scalar or vector of frequencies
tuning : float
Tuning deviation from A440 in (fractional) bins per octave.
bins_per_octave : int > 0
Number of bins per octave.
Returns
-------
octaves : number or np.ndarray [shape=(n,)]
octave number for each frequency
See Also
--------
octs_to_hz
"""
A440 = 440.0 * 2.0**(tuning / bins_per_octave)
return np.log2(np.asanyarray(frequencies) / (float(A440) / 16))
def octs_to_hz(octs, tuning=0.0, bins_per_octave=12):
"""Convert octaves numbers to frequencies.
Octaves are counted relative to A.
Examples
--------
>>> librosa.octs_to_hz(1)
55.
>>> librosa.octs_to_hz([-2, -1, 0, 1, 2])
array([ 6.875, 13.75 , 27.5 , 55. , 110. ])
Parameters
----------
octaves : np.ndarray [shape=(n,)] or float
octave number for each frequency
tuning : float
Tuning deviation from A440 in (fractional) bins per octave.
bins_per_octave : int > 0
Number of bins per octave.
Returns
-------
frequencies : number or np.ndarray [shape=(n,)]
scalar or vector of frequencies
See Also
--------
hz_to_octs
"""
A440 = 440.0 * 2.0**(tuning / bins_per_octave)
return (float(A440) / 16)*(2.0**np.asanyarray(octs))
def A4_to_tuning(A4, bins_per_octave=12):
"""Convert a reference pitch frequency (e.g., `A4=435`) to a tuning
estimation, in fractions of a bin per octave.
This is useful for determining the tuning deviation relative to
A440 of a given frequency, assuming equal temperament. By default,
12 bins per octave are used.
This method is the inverse of `tuning_to_A4`.
Examples
--------
The base case of this method in which A440 yields 0 tuning offset
from itself.
>>> librosa.A4_to_tuning(440.0)
0.
Convert a non-A440 frequency to a tuning offset relative
to A440 using the default of 12 bins per octave.
>>> librosa.A4_to_tuning(432.0)
-0.318
Convert two reference pitch frequencies to corresponding
tuning estimations at once, but using 24 bins per octave.
>>> librosa.A4_to_tuning([440.0, 444.0], bins_per_octave=24)
array([ 0., 0.313 ])
Parameters
----------
A4: float or np.ndarray [shape=(n,), dtype=float]
Reference frequency(s) corresponding to A4.
bins_per_octave : int > 0
Number of bins per octave.
Returns
-------
tuning : float or np.ndarray [shape=(n,), dtype=float]
Tuning deviation from A440 in (fractional) bins per octave.
See Also
--------
tuning_to_A4
"""
return bins_per_octave * (np.log2(np.asanyarray(A4)) - np.log2(440.0))
def tuning_to_A4(tuning, bins_per_octave=12):
"""Convert a tuning deviation (from 0) in fractions of a bin per
octave (e.g., `tuning=-0.1`) to a reference pitch frequency
relative to A440.
This is useful if you are working in a non-A440 tuning system
to determine the reference pitch frequency given a tuning
offset and assuming equal temperament. By default, 12 bins per
octave are used.
This method is the inverse of `A4_to_tuning`.