changeset 72:642df7b3346f

Support returning a magnitude spectrum (dense) etc
author Chris Cannam <c.cannam@qmul.ac.uk>
date Thu, 20 Mar 2014 16:15:43 +0000
parents 4767faa6726f
children be277d1367f4
files yeti/cqt.yeti yeti/cqtkernel.yeti yeti/nbproject/ide-file-targets.xml yeti/nbproject/project.xml yeti/plotfile.yeti yeti/test_frequency.yeti
diffstat 6 files changed, 164 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- a/yeti/cqt.yeti	Wed Mar 19 10:30:20 2014 +0000
+++ b/yeti/cqt.yeti	Thu Mar 20 16:15:43 2014 +0000
@@ -33,6 +33,7 @@
 cqtkernel = load cqtkernel;
 resample = load may.stream.resample;
 manipulate = load may.stream.manipulate;
+mat = load may.matrix;
 cm = load may.matrix.complex;
 framer = load may.stream.framer;
 cplx = load may.complex;
@@ -175,7 +176,36 @@
         done { rows, columns };
         );
 
-    processOctaveLists octs =
+    assembleBlockSpectrogram bits =
+       (// As assembleBlock, but producing a dense magnitude
+        // spectrogram (rather than a complex output with zeros
+        // between the cell values in lower octaves). (todo: smoothing)
+
+        //eprintln "assembleBlockSpectrogram: structure of bits is:";
+        //eprintln (map length bits);
+
+        rows = octaves * kdata.binsPerOctave;
+        columns = (pow 2 (octaves - 1)) * kdata.atomsPerFrame;
+
+        mat.generate do row col:
+
+            oct = int (row / binsPerOctave);
+            binNo = row % kdata.binsPerOctave;
+
+            chunks = pow 2 oct;
+            colsPerAtom = int (columns / (chunks * kdata.atomsPerFrame));
+            atomNo = int (col / colsPerAtom);
+
+            if atomNo < length bits[oct] then
+                cplx.magnitude bits[oct][atomNo][binNo];
+            else 
+                0
+            fi;
+
+        done { rows, columns };
+        );
+
+    processOctaveLists assembler octs =
         case octs[0] of
         block::rest:
            (toAssemble = array 
@@ -189,7 +219,7 @@
                         array []
                     fi
                 done (keys octs));
-            assembleBlock toAssemble :. \(processOctaveLists octs));
+            assembler toAssemble :. \(processOctaveLists assembler octs));
          _: []
         esac;
 
@@ -218,7 +248,14 @@
                     done (reverse (list kdata.binFrequencies))
                 done [0..octaves-1])
         },
-        output = processOctaveLists octaveLists
+        octaves,
+        output type =
+            case type of
+            ComplexCQ ():
+                Complex (processOctaveLists assembleBlock octaveLists);
+            Spectrogram ():
+                Real (processOctaveLists assembleBlockSpectrogram octaveLists);
+            esac
     }
     );
 
--- a/yeti/cqtkernel.yeti	Wed Mar 19 10:30:20 2014 +0000
+++ b/yeti/cqtkernel.yeti	Thu Mar 20 16:15:43 2014 +0000
@@ -124,7 +124,7 @@
     wx1 = vec.maxindex (complex.magnitudes (cm.getRow 0 kmat));
     wx2 = vec.maxindex (complex.magnitudes (cm.getRow (cm.height kmat - 1) kmat));
 
-    subset = cm.columnSlice kmat wx1 (wx2+1);
+    subset = cm.flipped (cm.columnSlice kmat wx1 (wx2+1));
     square = cm.product (cm.conjugateTransposed subset) subset;
 
     diag = complex.magnitudes (cm.getDiagonal 0 square);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/yeti/nbproject/ide-file-targets.xml	Thu Mar 20 16:15:43 2014 +0000
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project basedir=".." name="cqt-IDE">
+    <!-- TODO: edit the following target according to your needs -->
+    <!-- (more info: http://www.netbeans.org/kb/articles/freeform-config.html#debugj2se) -->
+    <property name="maydir" value="${basedir}/../../may"/>
+    <property name="yetidir" value="${basedir}/../../yeti"/>
+    <property name="jardir" value="${maydir}/ext/jar"/>
+        <path id="cp">
+            <fileset dir="${basedir}">
+                <include name="cqt.jar"/>
+            </fileset>
+            <fileset dir="${jardir}">
+                <include name="*.jar"/>
+            </fileset>
+            <fileset dir="${yetidir}">
+                <include name="yeti.jar"/>
+            </fileset>
+            <fileset dir="${maydir}">
+                <include name="may.jar"/>
+            </fileset>
+        </path>
+    <target name="debug-nb">
+        <nbjpdastart addressproperty="jpda.address" name="cqt" transport="dt_socket">
+            <classpath refid="cp"/>
+        </nbjpdastart>
+        <!-- TODO configure the main class for your project here: -->
+        <java classname="plotfile" fork="true">
+            <classpath refid="cp"/>
+            <jvmarg value="-Xdebug"/>
+            <jvmarg value="-Xrunjdwp:transport=dt_socket,address=${jpda.address}"/>
+            <arg value="${basedir}/test.wav"/>
+        </java>
+    </target>
+    <target name="-profile-check">
+        <startprofiler freeform="true"/>
+    </target>
+    <!-- TODO: edit the following target according to your needs -->
+    <!-- (more info: http://netbeans.org/kb/articles/freeform-config.html#profilej2se) -->
+    <target depends="-profile-check" if="profiler.configured" name="profile-nb">
+        <!-- TODO configure the main class for your project here: -->
+        <java classname="plotfile" fork="true">
+            <classpath refid="cp"/>
+            <jvmarg line="${agent.jvmargs}"/>
+            <arg value="${basedir}/test.wav"/>
+        </java>
+    </target>
+</project>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/yeti/nbproject/project.xml	Thu Mar 20 16:15:43 2014 +0000
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://www.netbeans.org/ns/project/1">
+    <type>org.netbeans.modules.ant.freeform</type>
+    <configuration>
+        <general-data xmlns="http://www.netbeans.org/ns/freeform-project/1">
+            <!-- Do not use Project Properties customizer when editing this file manually. 
+ To prevent the customizer from showing, create nbproject/project.properties file and enter 
+auxiliary.show.customizer=false 
+property there. Adding 
+auxiliary.show.customizer.message=<message>
+ will show your customized message when someone attempts to open the customizer.  -->
+            <name>cqt</name>
+            <properties/>
+            <folders/>
+            <ide-actions>
+                <action name="build">
+                    <target>jar</target>
+                </action>
+                <action name="clean">
+                    <target>clean</target>
+                </action>
+                <action name="rebuild">
+                    <target>clean</target>
+                    <target>jar</target>
+                </action>
+                <action name="debug">
+                    <script>nbproject/ide-file-targets.xml</script>
+                    <target>debug-nb</target>
+                </action>
+                <action name="profile">
+                    <script>nbproject/ide-file-targets.xml</script>
+                    <target>profile-nb</target>
+                </action>
+            </ide-actions>
+            <view>
+                <items>
+                    <source-file>
+                        <location>build.xml</location>
+                    </source-file>
+                </items>
+                <context-menu>
+                    <ide-action name="build"/>
+                    <ide-action name="rebuild"/>
+                    <ide-action name="clean"/>
+                    <ide-action name="debug"/>
+                    <ide-action name="profile"/>
+                </context-menu>
+            </view>
+            <subprojects/>
+        </general-data>
+        <java-data xmlns="http://www.netbeans.org/ns/freeform-project-java/1"/>
+    </configuration>
+</project>
--- a/yeti/plotfile.yeti	Wed Mar 19 10:30:20 2014 +0000
+++ b/yeti/plotfile.yeti	Thu Mar 20 16:15:43 2014 +0000
@@ -8,23 +8,34 @@
 
 { cqt } = load cqt;
 
+minFreq = 27.5;
+maxRateDivisor = 3;
+binsPerOctave = 60;
+
 plotfile f =
    (testStream = af.open f;
     eprintln "Opened file stream...";
+    start = System#currentTimeMillis();
     cq = cqt {
-        maxFreq = testStream.sampleRate/2, 
-        minFreq = 50, 
-        binsPerOctave = 24
+        maxFreq = testStream.sampleRate/maxRateDivisor, 
+        minFreq, 
+        binsPerOctave
         } testStream;
-    eprintln "Generated kernel and primed transform, now calculating...";
-    bigM = mat.concatHorizontal (map cm.magnitudes cq.output);
+    middle = System#currentTimeMillis();
+    eprintln "Generated kernel \(cm.size cq.kernel.kernel) and primed transform (\(cq.octaves) octaves), took \(middle-start)ms, now calculating...";
+    bigM = case (cq.output (Spectrogram ())) of
+        Real s: mat.concatHorizontal s;
+        _: failWith "Real expected";
+    esac;
+    finish = System#currentTimeMillis();
+    eprintln "Done, that part took \(finish-middle)ms, all CQ stuff took \(finish-start)ms";
     eprintln "Plotting...";
     \() (plot.plot [Contour bigM]));
 
 usage () =
    (eprintln "\nUsage: plotfile file.wav";
-    eprintln "\n   Loads audio from file.wav and plots a 24bpo Constant-Q spectrogram";
-    eprintln "   from 50Hz up to half the file samplerate");
+    eprintln "\n   Loads audio from file.wav and plots a \(binsPerOctave)bpo Constant-Q spectrogram";
+    eprintln "   from \(minFreq)Hz up to 1/\(maxRateDivisor) of the file samplerate");
 
 case (list _argv) of
 file::[]: plotfile file;
--- a/yeti/test_frequency.yeti	Wed Mar 19 10:30:20 2014 +0000
+++ b/yeti/test_frequency.yeti	Thu Mar 20 16:15:43 2014 +0000
@@ -81,7 +81,11 @@
     do f: \(
         str = streamBuilder f;
         cq = cqt { maxFreq = cqmax, minFreq = cqmin, binsPerOctave = bpo } str;
-        m = mat.concatHorizontal (map cm.magnitudes cq.output);
+        out = case cq.output (ComplexCQ ()) of
+            Complex c: c;
+            _: failWith "expected complex";
+        esac;
+        m = mat.concatHorizontal (map cm.magnitudes out);
 //    println "binFrequencies = \(cq.kernel.binFrequencies)";
 //    println "binForFreq \(f) = \(binForFreq f)";
         var colno = 0;