c@10
|
1
|
c@17
|
2 module cqt;
|
c@10
|
3
|
c@10
|
4 cqtkernel = load cqtkernel;
|
c@10
|
5 resample = load may.stream.resample;
|
c@10
|
6 manipulate = load may.stream.manipulate;
|
c@10
|
7 syn = load may.stream.syntheticstream;
|
c@10
|
8 cm = load may.matrix.complex;
|
c@10
|
9 mat = load may.matrix;
|
c@10
|
10 framer = load may.stream.framer;
|
c@10
|
11 cplx = load may.complex;
|
c@10
|
12 fft = load may.transform.fft;
|
c@10
|
13 vec = load may.vector;
|
c@17
|
14 af = load may.stream.audiofile;
|
c@10
|
15
|
c@10
|
16 { pow, round, floor, ceil, log2, nextPowerOfTwo } = load may.mathmisc;
|
c@10
|
17
|
c@10
|
18 cqt str =
|
c@10
|
19 (sampleRate = str.sampleRate;
|
c@10
|
20 maxFreq = sampleRate/2;
|
c@10
|
21 minFreq = 40;
|
c@10
|
22 binsPerOctave = 24;
|
c@10
|
23
|
c@16
|
24 eprintln "Here";
|
c@10
|
25
|
c@10
|
26 octaves = ceil (log2 (maxFreq / minFreq));
|
c@10
|
27
|
c@16
|
28 eprintln "Here: about to calculate stuff with \(octaves)";
|
c@10
|
29
|
c@10
|
30 actualMinFreq = (maxFreq / (pow 2 octaves)) * (pow 2 (1/binsPerOctave));
|
c@10
|
31
|
c@16
|
32 eprintln "sampleRate = \(sampleRate), maxFreq = \(maxFreq), minFreq = \(minFreq), actualMinFreq = \(actualMinFreq), octaves = \(octaves), binsPerOctave = \(binsPerOctave)";
|
c@10
|
33
|
c@10
|
34 kdata = cqtkernel.makeKernel { sampleRate, maxFreq, binsPerOctave };
|
c@10
|
35
|
c@16
|
36 eprintln "atomsPerFrame = \(kdata.atomsPerFrame)";
|
c@11
|
37
|
c@10
|
38 streams = manipulate.duplicated octaves str;
|
c@10
|
39
|
c@10
|
40 //!!! can't be right!
|
c@10
|
41 kernel = cm.transposed (cm.conjugateTransposed kdata.kernel);
|
c@10
|
42
|
c@16
|
43 eprintln "have kernel";
|
c@10
|
44
|
c@10
|
45 fftFunc = fft.forward kdata.fftSize;
|
c@10
|
46
|
c@10
|
47 cqblocks =
|
c@10
|
48 map do octave:
|
c@10
|
49 frames = framer.monoFrames //!!! mono for now
|
c@10
|
50 { framesize = kdata.fftSize, hop = kdata.fftHop }
|
c@10
|
51 (resample.decimated (pow 2 octave) streams[octave]);
|
c@10
|
52 map do frame:
|
c@10
|
53 freq = fftFunc (cplx.complexArray frame (vec.zeros kdata.fftSize));
|
c@10
|
54 cm.product kernel (cm.newComplexColumnVector freq);
|
c@10
|
55 done frames;
|
c@10
|
56 done [0..octaves-1];
|
c@10
|
57
|
c@13
|
58 // The cqblocks list is a list<list<matrix>>. Each top-level list
|
c@11
|
59 // corresponds to an octave, from highest to lowest, each having
|
c@11
|
60 // twice as many elements in its list as the next octave. The
|
c@11
|
61 // sub-lists are sampled in time with an effective spacing of
|
c@11
|
62 // fftSize * 2^(octave-1) audio frames, and the matrices are row
|
c@11
|
63 // vectors with atomsPerFrame * binsPerOctave complex elements.
|
c@13
|
64 //
|
c@13
|
65 // ***
|
c@13
|
66 //
|
c@13
|
67 // In a typical constant-Q structure, each (2^(octaves-1) *
|
c@13
|
68 // fftHop) input frames gives us an output structure conceptually
|
c@13
|
69 // like this:
|
c@10
|
70 //
|
c@10
|
71 // [][][][][][][][] <- fftHop frames per highest-octave output value
|
c@10
|
72 // [][][][][][][][] layered as many times as binsPerOctave (here 2)
|
c@10
|
73 // [--][--][--][--] <- fftHop*2 frames for the next lower octave
|
c@10
|
74 // [--][--][--][--] etc
|
c@10
|
75 // [------][------]
|
c@10
|
76 // [------][------]
|
c@10
|
77 // [--------------]
|
c@10
|
78 // [--------------]
|
c@10
|
79 //
|
c@13
|
80 // ***
|
c@13
|
81 //
|
c@13
|
82 // But the kernel we're using here has more than one temporally
|
c@13
|
83 // spaced atom; each individual cell is a row vector with
|
c@13
|
84 // atomsPerFrame * binsPerOctave elements, but that actually
|
c@13
|
85 // represents a rectangular matrix of result cells with width
|
c@13
|
86 // atomsPerFrame and height binsPerOctave. The columns of this
|
c@13
|
87 // matrix (the atoms) then need to be spaced by 2^(octave-1)
|
c@13
|
88 // relative to those from the highest octave.
|
c@10
|
89
|
c@15
|
90 // Reshape each row vector into the appropriate rectangular matrix
|
c@17
|
91 cqblocks = array (map do octlist:
|
c@14
|
92 map do rv:
|
c@15
|
93 cm.generate do row col:
|
c@15
|
94 cm.at rv ((row * kdata.atomsPerFrame) + col) 0
|
c@15
|
95 done {
|
c@15
|
96 rows = kdata.binsPerOctave,
|
c@15
|
97 columns = kdata.atomsPerFrame
|
c@15
|
98 }
|
c@14
|
99 done octlist
|
c@17
|
100 done cqblocks);
|
c@14
|
101
|
c@17
|
102 assembleBlock bits =
|
c@17
|
103 (println "assembleBlock: structure of bits is:";
|
c@17
|
104 println (map length bits);
|
c@17
|
105 []);
|
c@15
|
106
|
c@17
|
107 processOctaveLists octs =
|
c@17
|
108 case octs[0] of
|
c@17
|
109 block::rest:
|
c@17
|
110 (toAssemble =
|
c@17
|
111 map do oct:
|
c@17
|
112 n = pow 2 oct;
|
c@17
|
113 if not empty? octs[oct] then
|
c@17
|
114 forBlock = take n octs[oct];
|
c@17
|
115 octs[oct] := drop n octs[oct];
|
c@17
|
116 forBlock
|
c@17
|
117 else
|
c@17
|
118 []
|
c@17
|
119 fi
|
c@17
|
120 done (keys octs);
|
c@17
|
121 assembleBlock toAssemble :. \(processOctaveLists octs));
|
c@17
|
122 _: []
|
c@15
|
123 esac;
|
c@15
|
124
|
c@17
|
125 println "cqblocks has \(length cqblocks) entries";
|
c@15
|
126
|
c@17
|
127 octaveLists = [:];
|
c@17
|
128
|
c@17
|
129 for [1..octaves] do oct:
|
c@17
|
130 octaveLists[octaves - oct] := cqblocks[oct-1];
|
c@17
|
131 done;
|
c@17
|
132 /*
|
c@17
|
133 \() (map2 do octlist octave:
|
c@17
|
134 println "oct \(octaves) - \(octave) = \(octaves - octave)";
|
c@17
|
135 octaveLists[octaves - octave] := octlist
|
c@17
|
136 done cqblocks [1..octaves]);
|
c@17
|
137 */
|
c@17
|
138 println "octaveLists keys are: \(keys octaveLists)";
|
c@17
|
139
|
c@17
|
140 processOctaveLists octaveLists;
|
c@15
|
141
|
c@10
|
142 );
|
c@10
|
143
|
c@17
|
144 //testStream = manipulate.withDuration 96000 (syn.sinusoid 48000 500);
|
c@17
|
145 //testStream = manipulate.withDuration 96000 (syn.pulseTrain 48000 4);
|
c@17
|
146 testStream = af.open "sweep.wav";
|
c@10
|
147
|
c@16
|
148 eprintln "have test stream";
|
c@10
|
149
|
c@17
|
150 /*
|
c@16
|
151 c = cqt testStream;
|
c@10
|
152
|
c@16
|
153 thing = take 50 (drop 200 c);
|
c@16
|
154 m = cm.newComplexMatrix (ColumnMajor ()) thing;
|
c@16
|
155 mm = cm.magnitudes m;
|
c@10
|
156
|
c@16
|
157 for (mat.asColumns mm) (println . strJoin "," . vec.list);
|
c@10
|
158
|
c@16
|
159 ()
|
c@16
|
160
|
c@17
|
161 */
|
c@16
|
162
|
c@17
|
163 cqt testStream;
|
c@16
|
164
|