changeset 105:abbc482aaad2

* Switch CutThread to AsynchronousTask; introduce FFTThread as well and make the FFT calculations concurrent
author Chris Cannam <c.cannam@qmul.ac.uk>
date Tue, 12 May 2009 21:05:44 +0000
parents d8ad747eb907
children 35f2138c6891
files plugins/AdaptiveSpectrogram.cpp plugins/AdaptiveSpectrogram.h
diffstat 2 files changed, 91 insertions(+), 105 deletions(-) [+]
line wrap: on
line diff
--- a/plugins/AdaptiveSpectrogram.cpp	Tue May 12 17:57:41 2009 +0000
+++ b/plugins/AdaptiveSpectrogram.cpp	Tue May 12 21:05:44 2009 +0000
@@ -32,19 +32,20 @@
     m_w(8),
     m_n(3),
     m_first(true)
-//    m_w(0),
-//    m_n(2)
 {
 }
 
 AdaptiveSpectrogram::~AdaptiveSpectrogram()
 {
     for (int i = 0; i < m_cutThreads.size(); ++i) {
-        m_cutThreads[i]->finish();
-        m_cutThreads[i]->wait();
         delete m_cutThreads[i];
     }
     m_cutThreads.clear();
+
+    for (int i = 0; i < m_fftThreads.size(); ++i) {
+        delete m_fftThreads[i];
+    }
+    m_fftThreads.clear();
 }
 
 string
@@ -101,6 +102,10 @@
     if (channels < getMinChannelCount() ||
 	channels > getMaxChannelCount()) return false;
 
+    while (m_fftThreads.size() < (m_n + 1)) {
+        m_fftThreads.push_back(new FFTThread());
+    }
+    
     return true;
 }
 
@@ -219,37 +224,24 @@
 #endif
 
     Spectrograms s(minwid/2, maxwid/2, 1);
-    
-    double *tmpin  = new double[maxwid];
-    double *tmprout = new double[maxwid];
-    double *tmpiout = new double[maxwid];
 
     int w = minwid;
     int index = 0;
 
     while (w <= maxwid) {
-        for (int i = 0; i < maxwid / w; ++i) {
-            int origin = maxwid/4 - w/4; // for 50% overlap
-            for (int j = 0; j < w; ++j) {
-                double mul = 0.50 - 0.50 * cos((2 * M_PI * j) / w);
-                tmpin[j] = inputBuffers[0][origin + i * w/2 + j] * mul;
-            }
-            FFT::process(w, false, tmpin, 0, tmprout, tmpiout);
-            for (int j = 0; j < w/2; ++j) {
-                int k = j+1; // include Nyquist but not DC
-                double mag = sqrt(tmprout[k] * tmprout[k] +
-                                  tmpiout[k] * tmpiout[k]);
-                double scaled = mag / (w/2);
-                s.spectrograms[index]->data[i][j] = scaled;
-            }
-        }
+        m_fftThreads[index]->calculate(inputBuffers[0], s, index, w, maxwid);
         w *= 2;
         ++index;
     }
 
-    delete[] tmpin;
-    delete[] tmprout;
-    delete[] tmpiout;
+    w = minwid;
+    index = 0;
+
+    while (w <= maxwid) {
+        m_fftThreads[index]->await();
+        w *= 2;
+        ++index;
+    }
 
     m_first = true;//!!!
 
@@ -303,7 +295,6 @@
                                 Cutting *&top, Cutting *&bottom,
                                 Cutting *&left, Cutting *&right) const
 {
-    m_first = false;
     if (m_first) {//!!!
 
         m_first = false;
@@ -312,7 +303,7 @@
             for (int i = 0; i < 4; ++i) {
 //            for (int i = 0; i < 1; ++i) {
                 CutThread *t = new CutThread(this);
-                t->start();
+//                t->start();
                 m_cutThreads.push_back(t);
             }
 //            sleep(1); //!!!
--- a/plugins/AdaptiveSpectrogram.h	Tue May 12 17:57:41 2009 +0000
+++ b/plugins/AdaptiveSpectrogram.h	Tue May 12 21:05:44 2009 +0000
@@ -14,6 +14,8 @@
 #include <cmath>
 #include <vector>
 
+#include <dsp/transforms/FFT.h>//!!!
+
 #include "thread/Thread.h"
 
 class AdaptiveSpectrogram : public Vamp::Plugin
@@ -110,108 +112,101 @@
         }
     };
 
-    class CutThread : public Thread
+    class FFTThread : public AsynchronousTask
     {
     public:
-        CutThread(const AdaptiveSpectrogram *as) :
-            m_as(as),
-//            m_busy(false),
-//            m_computed(false),
-            m_result(0),
-            m_workToDoC("CutThread: work to do"),
-            m_workToDo(false),
-            m_workDoneC("CutThread: work done"),
-            m_workDone(false),
-            m_finishing(false)
-        { }
+        FFTThread() { }
+        ~FFTThread() { }
+
+        void calculate(const float *timeDomain, Spectrograms &s,
+                       int res, int width, int maxwidth) {
+            m_in = timeDomain;
+            m_s = &s;
+            m_res = res;
+            m_w = width;
+            m_maxwid = maxwidth;
+            startTask();
+        }
+
+        void await() {
+            awaitTask();
+        }
+
+    protected:
+        void performTask() {
+
+            double *tmpin   = new double[m_w];
+            double *tmprout = new double[m_w];
+            double *tmpiout = new double[m_w];
+
+            //!!! use window object
+
+            for (int i = 0; i < m_maxwid / m_w; ++i) {
+                int origin = m_maxwid/4 - m_w/4; // for 50% overlap
+                for (int j = 0; j < m_w; ++j) {
+                    double mul = 0.50 - 0.50 * cos((2 * M_PI * j) / m_w);
+                    tmpin[j] = m_in[origin + i * m_w/2 + j] * mul;
+                }
+                FFT::process(m_w, false, tmpin, 0, tmprout, tmpiout);
+                for (int j = 0; j < m_w/2; ++j) {
+                    int k = j+1; // include Nyquist but not DC
+                    double mag = sqrt(tmprout[k] * tmprout[k] +
+                                      tmpiout[k] * tmpiout[k]);
+                    double scaled = mag / (m_w/2);
+                    m_s->spectrograms[m_res]->data[i][j] = scaled;
+                }
+            }
+
+            delete[] tmpin;
+            delete[] tmprout;
+            delete[] tmpiout;
+        }
+
+    private:
+        const float *m_in;
+        Spectrograms *m_s;
+        int m_res;
+        int m_w;
+        int m_maxwid;
+    };
+
+    std::vector<FFTThread *> m_fftThreads;
+
+    class CutThread : public AsynchronousTask
+    {
+    public:
+        CutThread(const AdaptiveSpectrogram *as) : m_as(as), m_result(0) { }
         ~CutThread() { }
-
+        
         void cut(const Spectrograms &s, int res, int x, int y, int h) {
-            m_workToDoC.lock();
-//            std::cerr << "locked in main thread" << std::endl;
             m_s = &s;
             m_res = res;
             m_x = x;
             m_y = y;
             m_h = h;
-//            m_busy = true;
-//            m_computed = false;
-            m_workToDo = true;
-            m_workDone = false;
-            m_workToDoC.signal();
-            m_workDoneC.lock();
-            m_workToDoC.unlock();
+            startTask();
         }
 
         Cutting *get() {
-//            std::cerr << "about to wait within main thread" << std::endl;
-            // m_workDoneC must be locked from prior call to cut()
-            while (!m_workDone) m_workDoneC.wait();
-//            std::cerr << "waited within main thread" << std::endl;
-//            m_workDoneC.lock();
-//            while (!m_computed) {
-//                std::cerr << "waiting within main thread" << std::endl;
-//                m_condition.wait();
-//            }
-            Cutting *c = m_result;
-            m_result = 0;
-            m_workDoneC.unlock();
-            return c;
-        }
-/*
-        bool busy() {
-            return m_busy;
-        }
-*/
-        void finish() {
-            m_finishing = true;
-            m_workToDoC.signal();
+            awaitTask();
+            return m_result;
         }
 
     protected:
-        virtual void run() {
-            m_workToDoC.lock();
-//            std::cerr << "locked within run function" << std::endl;
-            while (!m_finishing) {
-//                if (!m_busy) {
-//                    std::cerr << "waiting within run function" << std::endl;
-//                    m_condition.wait();
-//                }
-                    while (!m_workToDo && !m_finishing) m_workToDoC.wait();
-//                    std::cerr << "waited within run function" << std::endl;
-                if (m_finishing) {
-                    break;
-                }
-                if (m_workToDo) {
-//                    std::cerr << "cut thread " << this << ": calling cut" << std::endl;
-                    m_result = m_as->cut(*m_s, m_res, m_x, m_y, m_h);
-//                    std::cerr << "cut returning" << std::endl;
-//                    m_computed = true;
-//                    m_busy = false;
-                    m_workToDo = false;
-                    m_workDone = true;
-//                    std::cerr << "signalling completion from run function" << std::endl;
-                    m_workDoneC.signal();
-                }
-            }
-            m_workToDoC.unlock();
+        void performTask() {
+            m_result = m_as->cut(*m_s, m_res, m_x, m_y, m_h);
         }
 
+    private:
         const AdaptiveSpectrogram *m_as;
         const Spectrograms *m_s;
         int m_res;
         int m_x;
         int m_y;
         int m_h;
-//        bool m_busy;
-//        bool m_computed;
         Cutting *m_result;
-        Condition m_workToDoC;
-        bool m_workToDo;
-        Condition m_workDoneC;
-        bool m_workDone;
-        bool m_finishing;
     };
+
     mutable std::vector<CutThread *> m_cutThreads;//!!! mutable blargh
 
 ///!!!    Mutex m_threadMutex;