Mercurial > hg > silvet
diff yeti/timefreq.yeti @ 12:0f6db1895e1c
Prepare the ground for cqt and templates
author | Chris Cannam |
---|---|
date | Fri, 21 Mar 2014 17:14:44 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yeti/timefreq.yeti Fri Mar 21 17:14:44 2014 +0000 @@ -0,0 +1,98 @@ + +module timefreq; + +// Obtain the time-frequency representation (based on constant-Q +// transform) as transcription input + +af = load may.stream.audiofile; +mat = load may.matrix; +plot = load may.plot; +vec = load may.vector; + +{ pow } = load may.mathmisc; + +{ resampledTo } = load may.stream.resample; + +{ cqt } = load cqt; + +prepareTimeFrequency wavfile = + (stream = resampledTo 44100 (af.openMono wavfile); + + streamLength = + case stream.available of + Known n: n; + _: failWith "Audio file length unknown?!"; + esac; + + eprintln "streamLength = \(streamLength)"; + + //!!! original also scales to peak = 0.5 + + cq = cqt { + maxFreq = stream.sampleRate / 3, + minFreq = 27.5, + binsPerOctave = 60 + } stream; + + //!!! note: original also modifies the Q and atomHopFactor + eprintln "atomSpacing = \(cq.kernel.atomSpacing)"; + + matrices = case cq.output (Spectrogram ()) of + Real mm: mm; + _: failWith "Expected real"; + esac; + + eprintln "have \(length matrices) matrices of size \(mat.size (head matrices)), isRowMajor? = \(mat.isRowMajor? (head matrices))"; + + levels = concatMap do m: + map do c: vec.sum c done (mat.asColumns m); + done matrices; + + nztail = find (> 0.1) levels; + nzonly = reverse (find (> 0.1) (reverse nztail)); + + eprintln "non-zero columns start at \(length levels - length nztail), go on for \(length nzonly) [of \(length levels)]"; + + nzstart = (length levels - length nztail) * cq.kernel.atomSpacing; + nzduration = (length nzonly) * cq.kernel.atomSpacing; + + // Get a stream of columns at 25 per second. + // + // The original picks samples at a rate of 100-per-second then + // median filters to reduce noise then picks samples again at + // 25-per-second. We don't do that (yet) + + samplesPerCol = stream.sampleRate / 25; + var sample = samplesPerCol - nzstart; + + columns = take (nzduration / samplesPerCol) + (concatMap do m: + concatMap do col: + sample := sample + cq.kernel.atomSpacing; + if sample >= samplesPerCol then + sample := sample - samplesPerCol; + [col] + else + [] + fi; + done (mat.asColumns m); + done matrices); + + eprintln "have \(length columns) columns of \(vec.length (head columns)) values each"; + + // drop the lowest 55 of the 600 bins + columns = map do c: + vec.slice c 55 (vec.length c); + done columns; + + eprintln "now have \(length columns) columns of \(vec.length (head columns))"; + +// plot.plot [ Grid (mat.fromColumns columns) ]; + + columns); + + +{ + prepareTimeFrequency +} +