c@10
|
1
|
c@10
|
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@10
|
14
|
c@10
|
15 { pow, round, floor, ceil, log2, nextPowerOfTwo } = load may.mathmisc;
|
c@10
|
16
|
c@10
|
17 cqt str =
|
c@10
|
18 (sampleRate = str.sampleRate;
|
c@10
|
19 maxFreq = sampleRate/2;
|
c@10
|
20 minFreq = 40;
|
c@10
|
21 binsPerOctave = 24;
|
c@10
|
22
|
c@10
|
23 println "Here";
|
c@10
|
24
|
c@10
|
25 octaves = ceil (log2 (maxFreq / minFreq));
|
c@10
|
26
|
c@10
|
27 println "Here: about to calculate stuff with \(octaves)";
|
c@10
|
28
|
c@10
|
29 actualMinFreq = (maxFreq / (pow 2 octaves)) * (pow 2 (1/binsPerOctave));
|
c@10
|
30
|
c@10
|
31 println "sampleRate = \(sampleRate), maxFreq = \(maxFreq), minFreq = \(minFreq), actualMinFreq = \(actualMinFreq), octaves = \(octaves), binsPerOctave = \(binsPerOctave)";
|
c@10
|
32
|
c@10
|
33 kdata = cqtkernel.makeKernel { sampleRate, maxFreq, binsPerOctave };
|
c@10
|
34
|
c@10
|
35 streams = manipulate.duplicated octaves str;
|
c@10
|
36
|
c@10
|
37 //!!! can't be right!
|
c@10
|
38 kernel = cm.transposed (cm.conjugateTransposed kdata.kernel);
|
c@10
|
39
|
c@10
|
40 println "have kernel";
|
c@10
|
41
|
c@10
|
42 fftFunc = fft.forward kdata.fftSize;
|
c@10
|
43
|
c@10
|
44 cqblocks =
|
c@10
|
45 map do octave:
|
c@10
|
46 frames = framer.monoFrames //!!! mono for now
|
c@10
|
47 { framesize = kdata.fftSize, hop = kdata.fftHop }
|
c@10
|
48 (resample.decimated (pow 2 octave) streams[octave]);
|
c@10
|
49 map do frame:
|
c@10
|
50 freq = fftFunc (cplx.complexArray frame (vec.zeros kdata.fftSize));
|
c@10
|
51 cm.product kernel (cm.newComplexColumnVector freq);
|
c@10
|
52 done frames;
|
c@10
|
53 done [0..octaves-1];
|
c@10
|
54
|
c@10
|
55 //!!! The comment below isn't true -- this is based on traditional
|
c@10
|
56 // cqt -- the atom hop structure for this version is different
|
c@10
|
57 // though so review later on
|
c@10
|
58
|
c@10
|
59 // Each (2^(octaves-1) * fftHop) input frames gives us an output
|
c@10
|
60 // structure conceptually like this:
|
c@10
|
61 //
|
c@10
|
62 // [][][][][][][][] <- fftHop frames per highest-octave output value
|
c@10
|
63 // [][][][][][][][] layered as many times as binsPerOctave (here 2)
|
c@10
|
64 // [--][--][--][--] <- fftHop*2 frames for the next lower octave
|
c@10
|
65 // [--][--][--][--] etc
|
c@10
|
66 // [------][------]
|
c@10
|
67 // [------][------]
|
c@10
|
68 // [--------------]
|
c@10
|
69 // [--------------]
|
c@10
|
70 //
|
c@10
|
71 // Our input is as a set of lazy frame lists, one list per octave.
|
c@10
|
72 // For each frame in the lowest octave
|
c@10
|
73
|
c@10
|
74 println "prepared block list";
|
c@10
|
75
|
c@10
|
76 cqblocks;
|
c@10
|
77
|
c@10
|
78 );
|
c@10
|
79
|
c@10
|
80 testStream = manipulate.withDuration 96000 (syn.sinusoid 48000 500);
|
c@10
|
81
|
c@10
|
82 println "have test stream";
|
c@10
|
83
|
c@10
|
84 cqt testStream;
|
c@10
|
85
|
c@10
|
86
|
c@10
|
87
|