pyACA: Documentation 0.3.1
Source Code for Audio Content Analysis
Loading...
Searching...
No Matches
computeKey.py
Go to the documentation of this file.
1# -*- coding: utf-8 -*-
2
3import numpy as np
4
5from pyACA.computeSpectrogram import computeSpectrogram
6from pyACA.ToolComputeHann import ToolComputeHann
7from pyACA.computeFeature import computeFeature
8
9
10
19def computeKey(x, f_s, afWindow=None, iBlockLength=4096, iHopLength=2048):
20
21 # compute window function for FFT
22 if afWindow is None:
23 afWindow = ToolComputeHann(iBlockLength)
24
25 assert(afWindow.shape[0] == iBlockLength), "parameter error: invalid window dimension"
26
27 # key names
28 cKeyNames = np.array(['C Maj', 'C# Maj', 'D Maj', 'D# Maj', 'E Maj', 'F Maj', 'F# Maj', 'G Maj', 'G# Maj', 'A Maj', 'A# Maj', 'B Maj',
29 'c min', 'c# min', 'd min', 'd# min', 'e min', 'f min', 'f# min', 'g min', 'g# min', 'a min', 'a# min', 'b min'])
30
31 # template pitch chroma (Krumhansl major/minor), normalized to a sum of 1
32 t_pc = np.array([[6.35, 2.23, 3.48, 2.33, 4.38, 4.09, 2.52, 5.19, 2.39, 3.66, 2.29, 2.88],
33 [6.33, 2.68, 3.52, 5.38, 2.60, 3.53, 2.54, 4.75, 3.98, 2.69, 3.34, 3.17]])
34 t_pc = t_pc / t_pc.sum(axis=1, keepdims=True)
35
36 # extract audio pitch chroma
37 v_pc, t = computeFeature("SpectralPitchChroma", x, f_s, afWindow, iBlockLength, iHopLength)
38
39 # average pitch chroma
40 v_pc = v_pc.mean(axis=1)
41
42 # compute manhattan distances for modes (major and minor)
43 d = np.zeros(t_pc.shape)
44 v_pc = np.concatenate((v_pc, v_pc), axis=0).reshape(2, 12)
45 for i in range(0, 12):
46 d[:, i] = np.sum(np.abs(v_pc - np.roll(t_pc, i, axis=1)), axis=1)
47
48 # get unwrapped key index
49 iKeyIdx = d.argmin()
50
51 cKey = cKeyNames[iKeyIdx]
52
53 return cKey
54
55
56
58def computeKeyCl(cPath):
59 from pyACA.ToolReadAudio import ToolReadAudio
60
61 [f_s, afAudioData] = ToolReadAudio(cPath)
62 # afAudioData = np.sin(2*np.pi * np.arange(f_s*1)*440./f_s)
63
64 cKey = computeKey(afAudioData, f_s)
65 print("\ndetected key: ", cKey)
66
67
68if __name__ == "__main__":
69 import argparse
70
71 parser = argparse.ArgumentParser(description='Compute key of wav file')
72 parser.add_argument('--infile', metavar='path', required=False,
73 help='path to input audio file')
74
75 args = parser.parse_args()
76 cPath = args.infile
77
78 # only for debugging
79 if not cPath:
80 cPath = "c:/temp/test.wav"
81
82 # call the function
83 computeKeyCl(cPath)
computeKeyCl(cPath)
main
Definition computeKey.py:58