Mercurial > hg > silvet
diff constant-q-cpp/misc/yeti/test_frequency.yeti @ 366:5d0a2ebb4d17
Bring dependent libraries in to repo
author | Chris Cannam |
---|---|
date | Fri, 24 Jun 2016 14:47:45 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/constant-q-cpp/misc/yeti/test_frequency.yeti Fri Jun 24 14:47:45 2016 +0100 @@ -0,0 +1,132 @@ +/* + Constant-Q library + Copyright (c) 2013-2014 Queen Mary, University of London + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without + restriction, including without limitation the rights to use, copy, + modify, merge, publish, distribute, sublicense, and/or sell copies + of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the names of the Centre for + Digital Music; Queen Mary, University of London; and Chris Cannam + shall not be used in advertising or otherwise to promote the sale, + use or other dealings in this Software without prior written + authorization. +*/ + +module test_frequency; + +mat = load may.matrix; +vec = load may.vector; +win = load may.signal.window; +mm = load may.mathmisc; +cm = load may.matrix.complex; +syn = load may.stream.syntheticstream; +plot = load may.plot; + +{ compare } = load may.test; + +{ cqt } = load cqt; + +// Test with a single windowed sinusoid, repeating at various frequencies + +sinTestStream sampleRate duration signalFreq = // duration is in samples + (sin = syn.sinusoid sampleRate signalFreq; + chunk = mat.getRow 0 (sin.read duration); + syn.precalculatedMono sampleRate (win.windowed win.hann chunk)); + +// We want to make a CQ transform spanning more than one octave, but +// not going all the way to fs/2 so we can test it also with +// frequencies above and below its extents + +sampleRate = 100; + +// fs/2 = 50 so 10->40 gives us 2 octaves +cqmin = 10; +cqmax = 40; +bpo = 4; // fairly arbitrary + +testFreqs = map (* 5) [ 0..10 ]; +duration = sampleRate * 2; + +threshold = 0.08; + +streamBuilder = sinTestStream sampleRate duration; + +binForFreq f = + mm.round (bpo * mm.log2 (f / cqmin)) - 1; + +report message matrix = + (eprintln message; + eprintln "matrix is:"; + mat.eprint matrix); +// chart = plot.plot [Grid matrix]; +// sleep 100; +// chart#dispose()); + +tests = mapIntoHash + do f: "freq_\(f)" done + do f: \( + str = streamBuilder f; + cq = cqt { maxFreq = cqmax, minFreq = cqmin, binsPerOctave = bpo } str; + spec = cq.cqSpectrogram; + rightSize = all id + (map do s: + compare (mat.size s) { + rows = cq.kernel.binsPerOctave * cq.octaves, + columns = cq.kernel.atomsPerFrame * mm.pow 2 (cq.octaves - 1) + } + done spec); + m = mat.concatHorizontal spec; +// println "binFrequencies = \(cq.kernel.binFrequencies)"; +// println "binForFreq \(f) = \(binForFreq f)"; + var colno = 0; + success = all id + (rightSize :: map do c: + // The test passes for this column if: + // + // * the max bin is the expected one, or + // + // * the expected max is out of range entirely (but + // we need to test _something_ in this case -- + // what?), or + // + // * all bins are below a threshold, or + // + // * this is an odd column and the expected max is in + // the lower octave + // + // We should also check that all values in the lower + // octave are zero for odd columns. + // + expected = binForFreq f; + good = + (expected < 0 or expected >= vec.length c) or + ((colno % 2 == 1) and expected < (vec.length c / 2)) or + (vec.max c < threshold) or + (vec.maxindex c == binForFreq f); + if (not good) then + report " * bad! maxindex \(vec.maxindex c) != expected \(binForFreq f) for freq \(f) in column \(colno) of \(mat.width m): column is \(vec.list c)" m; + fi; + colno := colno + 1; + good; + done (mat.asColumns m)); + success; + ) done + testFreqs; + +tests is hash<string, () -> boolean>