annotate yeti/icqt.yeti @ 101:4ad90a51a067

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