Mercurial > hg > silvet
comparison yeti/timefreq.yeti @ 12:0f6db1895e1c
Prepare the ground for cqt and templates
author | Chris Cannam |
---|---|
date | Fri, 21 Mar 2014 17:14:44 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
11:f268212ac499 | 12:0f6db1895e1c |
---|---|
1 | |
2 module timefreq; | |
3 | |
4 // Obtain the time-frequency representation (based on constant-Q | |
5 // transform) as transcription input | |
6 | |
7 af = load may.stream.audiofile; | |
8 mat = load may.matrix; | |
9 plot = load may.plot; | |
10 vec = load may.vector; | |
11 | |
12 { pow } = load may.mathmisc; | |
13 | |
14 { resampledTo } = load may.stream.resample; | |
15 | |
16 { cqt } = load cqt; | |
17 | |
18 prepareTimeFrequency wavfile = | |
19 (stream = resampledTo 44100 (af.openMono wavfile); | |
20 | |
21 streamLength = | |
22 case stream.available of | |
23 Known n: n; | |
24 _: failWith "Audio file length unknown?!"; | |
25 esac; | |
26 | |
27 eprintln "streamLength = \(streamLength)"; | |
28 | |
29 //!!! original also scales to peak = 0.5 | |
30 | |
31 cq = cqt { | |
32 maxFreq = stream.sampleRate / 3, | |
33 minFreq = 27.5, | |
34 binsPerOctave = 60 | |
35 } stream; | |
36 | |
37 //!!! note: original also modifies the Q and atomHopFactor | |
38 eprintln "atomSpacing = \(cq.kernel.atomSpacing)"; | |
39 | |
40 matrices = case cq.output (Spectrogram ()) of | |
41 Real mm: mm; | |
42 _: failWith "Expected real"; | |
43 esac; | |
44 | |
45 eprintln "have \(length matrices) matrices of size \(mat.size (head matrices)), isRowMajor? = \(mat.isRowMajor? (head matrices))"; | |
46 | |
47 levels = concatMap do m: | |
48 map do c: vec.sum c done (mat.asColumns m); | |
49 done matrices; | |
50 | |
51 nztail = find (> 0.1) levels; | |
52 nzonly = reverse (find (> 0.1) (reverse nztail)); | |
53 | |
54 eprintln "non-zero columns start at \(length levels - length nztail), go on for \(length nzonly) [of \(length levels)]"; | |
55 | |
56 nzstart = (length levels - length nztail) * cq.kernel.atomSpacing; | |
57 nzduration = (length nzonly) * cq.kernel.atomSpacing; | |
58 | |
59 // Get a stream of columns at 25 per second. | |
60 // | |
61 // The original picks samples at a rate of 100-per-second then | |
62 // median filters to reduce noise then picks samples again at | |
63 // 25-per-second. We don't do that (yet) | |
64 | |
65 samplesPerCol = stream.sampleRate / 25; | |
66 var sample = samplesPerCol - nzstart; | |
67 | |
68 columns = take (nzduration / samplesPerCol) | |
69 (concatMap do m: | |
70 concatMap do col: | |
71 sample := sample + cq.kernel.atomSpacing; | |
72 if sample >= samplesPerCol then | |
73 sample := sample - samplesPerCol; | |
74 [col] | |
75 else | |
76 [] | |
77 fi; | |
78 done (mat.asColumns m); | |
79 done matrices); | |
80 | |
81 eprintln "have \(length columns) columns of \(vec.length (head columns)) values each"; | |
82 | |
83 // drop the lowest 55 of the 600 bins | |
84 columns = map do c: | |
85 vec.slice c 55 (vec.length c); | |
86 done columns; | |
87 | |
88 eprintln "now have \(length columns) columns of \(vec.length (head columns))"; | |
89 | |
90 // plot.plot [ Grid (mat.fromColumns columns) ]; | |
91 | |
92 columns); | |
93 | |
94 | |
95 { | |
96 prepareTimeFrequency | |
97 } | |
98 |