annotate constant-q-cpp/misc/yeti/icqt.yeti @ 372:af71cbdab621 tip

Update bqvec code
author Chris Cannam
date Tue, 19 Nov 2019 10:13:32 +0000
parents 5d0a2ebb4d17
children
rev   line source
Chris@366 1 /*
Chris@366 2 Constant-Q library
Chris@366 3 Copyright (c) 2013-2014 Queen Mary, University of London
Chris@366 4
Chris@366 5 Permission is hereby granted, free of charge, to any person
Chris@366 6 obtaining a copy of this software and associated documentation
Chris@366 7 files (the "Software"), to deal in the Software without
Chris@366 8 restriction, including without limitation the rights to use, copy,
Chris@366 9 modify, merge, publish, distribute, sublicense, and/or sell copies
Chris@366 10 of the Software, and to permit persons to whom the Software is
Chris@366 11 furnished to do so, subject to the following conditions:
Chris@366 12
Chris@366 13 The above copyright notice and this permission notice shall be
Chris@366 14 included in all copies or substantial portions of the Software.
Chris@366 15
Chris@366 16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
Chris@366 17 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
Chris@366 18 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
Chris@366 19 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
Chris@366 20 CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
Chris@366 21 CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
Chris@366 22 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Chris@366 23
Chris@366 24 Except as contained in this notice, the names of the Centre for
Chris@366 25 Digital Music; Queen Mary, University of London; and Chris Cannam
Chris@366 26 shall not be used in advertising or otherwise to promote the sale,
Chris@366 27 use or other dealings in this Software without prior written
Chris@366 28 authorization.
Chris@366 29 */
Chris@366 30
Chris@366 31 module icqt;
Chris@366 32
Chris@366 33 cqt = load cqt;
Chris@366 34 cm = load may.matrix.complex;
Chris@366 35 framer = load may.stream.framer;
Chris@366 36 win = load may.signal.window;
Chris@366 37 mm = load may.mathmisc;
Chris@366 38 vec = load may.vector;
Chris@366 39 resamp = load may.stream.resample;
Chris@366 40 manip = load may.stream.manipulate;
Chris@366 41 mat = load may.matrix;
Chris@366 42
Chris@366 43 icqt cq =
Chris@366 44 (kdata = cq.kernel;
Chris@366 45
Chris@366 46 // kdata.kernel is the kernel matrix for a single octave. It has
Chris@366 47 // width kdata.fftSize and height kdata.binsPerOctave *
Chris@366 48 // kdata.atomsPerFrame.
Chris@366 49 //
Chris@366 50 // kdata.fftHop is the overlap between kernel matrices in a single
Chris@366 51 // octave.
Chris@366 52 //
Chris@366 53 // cq.sampleRate is the output stream sample rate and cq.octaves
Chris@366 54 // the number of octaves.
Chris@366 55 //
Chris@366 56 // cq.cqComplex is the list of complex matrices containing the CQ
Chris@366 57 // output. Each has width kdata.atomsPerFrame * 2^(cq.octaves-1)
Chris@366 58 // and height kdata.binsPerOctave * cq.octaves.
Chris@366 59
Chris@366 60 bpo = kdata.binsPerOctave;
Chris@366 61 atomsPerFrame = kdata.atomsPerFrame;
Chris@366 62 octaves = cq.octaves;
Chris@366 63
Chris@366 64 // transform a single block, all octaves tall, into an array
Chris@366 65 // (indexed by octave) of lists of individual columns (valid
Chris@366 66 // values for that octave only)
Chris@366 67 decomposeOctaves mat = array
Chris@366 68 (map do oct:
Chris@366 69 inverted = cm.fromRows (reverse (cm.asRows mat));
Chris@366 70 octMat = cm.rowSlice inverted (bpo * oct) (bpo * (oct + 1));
Chris@366 71 gap = (mm.pow 2 oct) - 1;
Chris@366 72 pickFrom cols =
Chris@366 73 case cols of
Chris@366 74 c::cs: c::(pickFrom (drop gap cs));
Chris@366 75 _: [];
Chris@366 76 esac;
Chris@366 77 pickFrom (cm.asColumns octMat);
Chris@366 78 done [0..octaves-1]);
Chris@366 79
Chris@366 80 // transform a list of the arrays produced by decomposeOctaves
Chris@366 81 // into a single array (indexed by octave) of lists of the
Chris@366 82 // individual columns
Chris@366 83 flattenOctaves decomposed =
Chris@366 84 (flattenAux acc decomposed =
Chris@366 85 case decomposed of
Chris@366 86 chunk::rest:
Chris@366 87 flattenAux
Chris@366 88 (array
Chris@366 89 (map do oct:
Chris@366 90 acc[oct] ++ chunk[oct]
Chris@366 91 done [0..octaves-1]))
Chris@366 92 rest;
Chris@366 93 _: acc;
Chris@366 94 esac;
Chris@366 95 flattenAux (array (map \[] [0..octaves-1])) decomposed);
Chris@366 96
Chris@366 97 // given a list of columns, deinterleave and pile up each sequence
Chris@366 98 // of atomsPerFrame columns into a single tall column and return
Chris@366 99 // the resulting list of tall columns
Chris@366 100 pile cols =
Chris@366 101 (pileAux acc cols =
Chris@366 102 if (length cols) >= atomsPerFrame then
Chris@366 103 atoms = take atomsPerFrame cols;
Chris@366 104 juggled = concat (reverse (cm.asRows (cm.fromColumns atoms)));
Chris@366 105 pileAux (juggled :: acc) (drop atomsPerFrame cols);
Chris@366 106 else
Chris@366 107 reverse acc
Chris@366 108 fi;
Chris@366 109 pileAux [] cols);
Chris@366 110
Chris@366 111 octaveColumnLists =
Chris@366 112 map pile (list (flattenOctaves (map decomposeOctaves cq.cqComplex)));
Chris@366 113
Chris@366 114 for octaveColumnLists do l: println "octave column list length: \(length l)" done;
Chris@366 115
Chris@366 116 kernel = cm.transposed kdata.kernel; // right way around for the multiply
Chris@366 117
Chris@366 118 spectra =
Chris@366 119 map do l:
Chris@366 120 map do col:
Chris@366 121 res = cm.transposed (cm.product kernel (cm.newComplexColumnVector col));
Chris@366 122 cm.columnSlice res 0 (kdata.fftSize / 2 + 1)
Chris@366 123 done l;
Chris@366 124 done octaveColumnLists;
Chris@366 125
Chris@366 126 eprintln "calculated spectra, now to ifft, overlap-add...";
Chris@366 127
Chris@366 128 rates = map do oct: cq.sampleRate / (mm.pow 2 oct) done [0..cq.octaves-1];
Chris@366 129
Chris@366 130 resynthesised =
Chris@366 131 map2 do frames rate:
Chris@366 132 framer.complexStreamed rate kdata.fftSize
Chris@366 133 [ FrequencyDomain true, Window win.boxcar, Hop kdata.fftHop ]
Chris@366 134 frames;
Chris@366 135 done spectra rates;
Chris@366 136
Chris@366 137 eprintln "have streams:";
Chris@366 138 for resynthesised eprintln;
Chris@366 139
Chris@366 140 resampled = map (resamp.resampledTo cq.sampleRate) resynthesised;
Chris@366 141
Chris@366 142 manip.sum resampled;
Chris@366 143 );
Chris@366 144
Chris@366 145 {icqt}