diff host/vamp-simple-host.cpp @ 64:9d3272c7db60

* Merge from host-factory-stuff branch: this adds several helper classes in the hostext directory that should make a host's life much easier. This will become version 1.1 of the SDK, eventually.
author cannam
date Fri, 01 Jun 2007 15:10:17 +0000
parents d3995d2b5e08
children 6d16c376fd2f
line wrap: on
line diff
--- a/host/vamp-simple-host.cpp	Fri Mar 30 17:14:16 2007 +0000
+++ b/host/vamp-simple-host.cpp	Fri Jun 01 15:10:17 2007 +0000
@@ -35,12 +35,14 @@
     authorization.
 */
 
-#include "PluginHostAdapter.h"
-#include "vamp.h"
+#include "vamp-sdk/PluginHostAdapter.h"
+#include "vamp-sdk/hostext/PluginChannelAdapter.h"
+#include "vamp-sdk/hostext/PluginInputDomainAdapter.h"
+#include "vamp-sdk/hostext/PluginLoader.h"
+#include "vamp/vamp.h"
 
 #include <iostream>
 #include <sndfile.h>
-#include <dirent.h> // POSIX directory open and read
 
 #include "system.h"
 
@@ -52,59 +54,62 @@
 using std::string;
 using std::vector;
 
-#define HOST_VERSION "1.0"
+using Vamp::HostExt::PluginLoader;
+
+#define HOST_VERSION "1.1"
 
 void printFeatures(int, int, int, Vamp::Plugin::FeatureSet);
 void transformInput(float *, size_t);
 void fft(unsigned int, bool, double *, double *, double *, double *);
-void printPluginPath();
+void printPluginPath(bool verbose);
+void enumeratePlugins();
+void listPluginsInLibrary(string soname);
+int runPlugin(string myname, string soname, string id, string output,
+              int outputNo, string inputFile);
 
-#ifdef HAVE_OPENDIR
-void enumeratePlugins();
-#endif
-
-/*
-    A very simple Vamp plugin host.  Given the name of a plugin
-    library and the name of a sound file on the command line, it loads
-    the first plugin in the library and runs it on the sound file,
-    dumping the plugin's first output to stdout.
-*/
+void usage(const char *name)
+{
+    cerr << "\n"
+         << name << ": A simple Vamp plugin host.\n\n"
+        "Centre for Digital Music, Queen Mary, University of London.\n"
+        "Copyright 2006-2007 Chris Cannam and QMUL.\n"
+        "Freely redistributable; published under a BSD-style license.\n\n"
+        "Usage:\n\n"
+        "  " << name << " pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin[:output] file.wav\n"
+        "  " << name << " pluginlibrary[." << PLUGIN_SUFFIX << "]:plugin file.wav [outputno]\n\n"
+        "    -- Load plugin id \"plugin\" from \"pluginlibrary\" and run it on the\n"
+        "       audio data in \"file.wav\"; retrieve the named \"output\", or output\n"
+        "       number \"outputno\" (the first output by default) and dump it to\n"
+        "       standard output.\n\n"
+        "  " << name << " -l\n\n"
+        "    -- List the plugin libraries and Vamp plugins in the plugin search path.\n\n"
+        "  " << name << " -p\n\n"
+        "    -- Print out the Vamp plugin search path.\n\n"
+        "  " << name << " -v\n\n"
+        "    -- Display version information only.\n\n"
+         << endl;
+    exit(2);
+}
 
 int main(int argc, char **argv)
 {
-    if (argc < 2 || argc > 4) {
-        char *scooter = argv[0];
-        char *name = 0;
-        while (scooter && *scooter) {
-            if (*scooter == '/' || *scooter == '\\') name = ++scooter;
-            else ++scooter;
-        }
-        if (!name || !*name) name = argv[0];
-        cerr << "\n"
-             << name << ": A simple Vamp plugin host.\n\n"
-            "Centre for Digital Music, Queen Mary, University of London.\n"
-            "Copyright 2006 Chris Cannam and QMUL.\n"
-            "Freely redistributable; published under a BSD-style license.\n\n"
-            "Usage:\n\n"
-            "  " << name << " pluginlibrary." << PLUGIN_SUFFIX << "\n\n"
-            "    -- Load \"pluginlibrary\" and list the Vamp plugins it contains.\n\n"
-            "  " << name << " pluginlibrary." << PLUGIN_SUFFIX << ":plugin file.wav [outputno]\n\n"
-            "    -- Load plugin id \"plugin\" from \"pluginlibrary\" and run it on the\n"
-            "       audio data in \"file.wav\", dumping the output from \"outputno\"\n"
-            "       (default 0) to standard output.\n\n"
-#ifdef HAVE_OPENDIR
-            "  " << name << " -l\n\n"
-            "    -- List the plugin libraries and Vamp plugins in the plugin search path.\n\n"
-#endif
-            "  " << name << " -p\n\n"
-            "    -- Print out the Vamp plugin search path.\n\n"
-	    "  " << name << " -v\n\n"
-	    "    -- Display version information only.\n\n"
-	    "Note that this host does not use the plugin search path when loadinga plugin.\nIf a plugin library is specified, it should be with a full file path.\n"
-             << endl;
-        return 2;
+    char *scooter = argv[0];
+    char *name = 0;
+    while (scooter && *scooter) {
+        if (*scooter == '/' || *scooter == '\\') name = ++scooter;
+        else ++scooter;
     }
+    if (!name || !*name) name = argv[0];
     
+    if (argc < 2 || argc > 4 ||
+        (argc == 2 &&
+         (!strcmp(argv[1], "-?") ||
+          !strcmp(argv[1], "-h") ||
+          !strcmp(argv[1], "--help")))) {
+
+        usage(name); // does not return
+    }
+
     if (argc == 2 && !strcmp(argv[1], "-v")) {
 	cout << "Simple Vamp plugin host version: " << HOST_VERSION << endl
 	     << "Vamp API version: " << VAMP_API_VERSION << endl
@@ -113,89 +118,57 @@
     }
     
     if (argc == 2 && !strcmp(argv[1], "-l")) {
-#ifdef HAVE_OPENDIR
+        printPluginPath(true);
         enumeratePlugins();
-#endif
         return 0;
     }
     if (argc == 2 && !strcmp(argv[1], "-p")) {
-        printPluginPath();
+        printPluginPath(false);
         return 0;
     }
 
-    cerr << endl << argv[0] << ": Running..." << endl;
+    cerr << endl << name << ": Running..." << endl;
 
     string soname = argv[1];
     string plugid = "";
+    string output = "";
+    int outputNo = -1;
     string wavname;
     if (argc >= 3) wavname = argv[2];
 
-    int sep = soname.find(":");
-    if (sep >= 0 && sep < int(soname.length())) {
+    string::size_type sep = soname.find(':');
+
+    if (sep != string::npos) {
         plugid = soname.substr(sep + 1);
         soname = soname.substr(0, sep);
-    }
 
-    void *libraryHandle = DLOPEN(soname, RTLD_LAZY);
-
-    if (!libraryHandle) {
-        cerr << argv[0] << ": Failed to open plugin library " 
-                  << soname << ": " << DLERROR() << endl;
-        return 1;
-    }
-
-    cerr << argv[0] << ": Opened plugin library " << soname << endl;
-
-    VampGetPluginDescriptorFunction fn = (VampGetPluginDescriptorFunction)
-        DLSYM(libraryHandle, "vampGetPluginDescriptor");
-    
-    if (!fn) {
-        cerr << argv[0] << ": No Vamp descriptor function in library "
-                  << soname << endl;
-        DLCLOSE(libraryHandle);
-        return 1;
-    }
-
-    cerr << argv[0] << ": Found plugin descriptor function" << endl;
-
-    int index = 0;
-    int plugnumber = -1;
-    const VampPluginDescriptor *descriptor = 0;
-
-    while ((descriptor = fn(VAMP_API_VERSION, index))) {
-
-        Vamp::PluginHostAdapter plugin(descriptor, 48000);
-        cerr << argv[0] << ": Plugin " << (index+1)
-                  << " is \"" << plugin.getIdentifier() << "\"" << endl;
-
-        if (plugin.getIdentifier() == plugid) plugnumber = index;
-        
-        ++index;
-    }
-
-    cerr << argv[0] << ": Done\n" << endl;
-
-    if (wavname == "") {
-        DLCLOSE(libraryHandle);
-        return 0;
-    }
-
-    if (plugnumber < 0) {
-        if (plugid != "") {
-            cerr << "ERROR: No such plugin as " << plugid << " in library"
-                 << endl;
-            DLCLOSE(libraryHandle);
-            return 0;
-        } else {
-            plugnumber = 0;
+        sep = plugid.find(':');
+        if (sep != string::npos) {
+            output = plugid.substr(sep + 1);
+            plugid = plugid.substr(0, sep);
         }
     }
 
-    descriptor = fn(VAMP_API_VERSION, plugnumber);
-    if (!descriptor) {
-        DLCLOSE(libraryHandle);
-        return 0;
+    if (plugid == "") {
+        usage(name);
     }
+
+    if (argc == 4) outputNo = atoi(argv[3]);
+
+    if (output != "" && outputNo != -1) {
+        usage(name);
+    }
+
+    return runPlugin(name, soname, plugid, output, outputNo, wavname);
+}
+
+
+int runPlugin(string myname, string soname, string id,
+              string output, int outputNo, string wavname)
+{
+    PluginLoader *loader = PluginLoader::getInstance();
+
+    PluginLoader::PluginKey key = loader->composePluginKey(soname, id);
     
     SNDFILE *sndfile;
     SF_INFO sfinfo;
@@ -203,48 +176,25 @@
 
     sndfile = sf_open(wavname.c_str(), SFM_READ, &sfinfo);
     if (!sndfile) {
-	cerr << "ERROR: Failed to open input file \"" << wavname << "\": "
-	     << sf_strerror(sndfile) << endl;
-        DLCLOSE(libraryHandle);
+	cerr << myname << ": ERROR: Failed to open input file \""
+             << wavname << "\": " << sf_strerror(sndfile) << endl;
 	return 1;
     }
 
-    Vamp::PluginHostAdapter *plugin =
-        new Vamp::PluginHostAdapter(descriptor, sfinfo.samplerate);
+    Vamp::Plugin *plugin = loader->loadPlugin
+        (key, sfinfo.samplerate, PluginLoader::ADAPT_ALL);
+    if (!plugin) {
+        cerr << myname << ": ERROR: Failed to load plugin \"" << id
+             << "\" from library \"" << soname << "\"" << endl;
+        sf_close(sndfile);
+        return 1;
+    }
 
-    cerr << "Running " << plugin->getIdentifier() << "..." << endl;
+    cerr << "Running plugin: \"" << plugin->getIdentifier() << "\"..." << endl;
 
     int blockSize = plugin->getPreferredBlockSize();
     int stepSize = plugin->getPreferredStepSize();
 
-    cerr << "Preferred block size = " << blockSize << ", step size = "
-         << stepSize << endl;
-
-    if (blockSize == 0) blockSize = 1024;
-
-    bool rightBlockSize = true;
-
-    if (plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) {
-
-        int p = 1, b = blockSize;
-        while (b) {
-            p <<= 1;
-            b >>= 1;
-        }
-        if (p != blockSize * 2) {
-            cerr << "WARNING: Plugin requested non-power-of-two block size of "
-                 << blockSize << ",\nwhich is not supported by this host.  ";
-            blockSize = p;
-            cerr << "Rounding up to " << blockSize << "." << endl;
-            rightBlockSize = false;
-        }
-        if (stepSize == 0) stepSize = blockSize / 2;
-
-    } else {
-
-        if (stepSize == 0) stepSize = blockSize;
-    }
-
     int channels = sfinfo.channels;
 
     float *filebuf = new float[blockSize * channels];
@@ -257,48 +207,47 @@
     int minch = plugin->getMinChannelCount();
     int maxch = plugin->getMaxChannelCount();
     cerr << "Plugin accepts " << minch << " -> " << maxch << " channel(s)" << endl;
+    cerr << "Sound file has " << channels << " (will mix/augment if necessary)" << endl;
 
     Vamp::Plugin::OutputList outputs = plugin->getOutputDescriptors();
     Vamp::Plugin::OutputDescriptor od;
 
     int returnValue = 1;
 
-    int output = 0;
-    if (argc == 4) output = atoi(argv[3]);
-
-    bool mix = false;
-
-    if (minch > channels || maxch < channels) {
-        if (minch == 1) {
-            cerr << "WARNING: Sound file has " << channels << " channels, mixing down to 1" << endl;
-            mix = true;
-            channels = 1;
-        } else {
-            cerr << "ERROR: Sound file has " << channels << " channels, out of range for plugin" << endl;
-            goto done;
-        }
-    }
-
     if (outputs.empty()) {
-	cerr << "Plugin has no outputs!" << endl;
+	cerr << "ERROR: Plugin has no outputs!" << endl;
         goto done;
     }
 
-    if (int(outputs.size()) <= output) {
-	cerr << "Output " << output << " requested, but plugin has only " << outputs.size() << " output(s)" << endl;
-        goto done;
-    }        
+    if (outputNo < 0) {
 
-    od = outputs[output];
-    cerr << "Output is " << od.identifier << endl;
+        for (size_t oi = 0; oi < outputs.size(); ++oi) {
+            if (outputs[oi].identifier == output) {
+                outputNo = oi;
+                break;
+            }
+        }
+
+        if (outputNo < 0) {
+            cerr << "ERROR: Non-existent output \"" << output << "\" requested" << endl;
+            goto done;
+        }
+
+    } else {
+
+        if (int(outputs.size()) <= outputNo) {
+            cerr << "ERROR: Output " << outputNo << " requested, but plugin has only " << outputs.size() << " output(s)" << endl;
+            goto done;
+        }        
+    }
+
+    od = outputs[outputNo];
+    cerr << "Output is: \"" << od.identifier << "\"" << endl;
 
     if (!plugin->initialise(channels, stepSize, blockSize)) {
         cerr << "ERROR: Plugin initialise (channels = " << channels
              << ", stepSize = " << stepSize << ", blockSize = "
              << blockSize << ") failed." << endl;
-        if (!rightBlockSize) {
-            cerr << "(Probably because I couldn't provide the plugin's preferred block size.)" << endl;
-        }
         goto done;
     }
 
@@ -317,141 +266,134 @@
         }
 
         for (int c = 0; c < channels; ++c) {
-            for (int j = 0; j < blockSize; ++j) {
+            int j = 0;
+            while (j < count) {
+                plugbuf[c][j] = filebuf[j * sfinfo.channels + c];
+                ++j;
+            }
+            while (j < blockSize) {
                 plugbuf[c][j] = 0.0f;
-            }
-        }
-
-        for (int j = 0; j < blockSize && j < count; ++j) {
-            int tc = 0;
-            for (int c = 0; c < sfinfo.channels; ++c) {
-                tc = c;
-                if (mix) tc = 0;
-                plugbuf[tc][j] += filebuf[j * sfinfo.channels + c];
-            }
-            if (mix) {
-                plugbuf[0][j] /= sfinfo.channels;
-            }
-        }
-
-        if (plugin->getInputDomain() == Vamp::Plugin::FrequencyDomain) {
-            for (int c = 0; c < sfinfo.channels; ++c) {
-                transformInput(plugbuf[c], blockSize);
-                if (mix) break;
+                ++j;
             }
         }
 
         printFeatures
-            (i, sfinfo.samplerate, output, plugin->process
+            (i, sfinfo.samplerate, outputNo, plugin->process
              (plugbuf, Vamp::RealTime::frame2RealTime(i, sfinfo.samplerate)));
     }
 
-    printFeatures(sfinfo.frames, sfinfo.samplerate, output,
+    printFeatures(sfinfo.frames, sfinfo.samplerate, outputNo,
                   plugin->getRemainingFeatures());
 
     returnValue = 0;
 
 done:
     delete plugin;
-
-    DLCLOSE(libraryHandle);
     sf_close(sndfile);
     return returnValue;
 }
 
 void
-printPluginPath()
+printPluginPath(bool verbose)
 {
+    if (verbose) {
+        cout << "\nVamp plugin search path: ";
+    }
+
     vector<string> path = Vamp::PluginHostAdapter::getPluginPath();
     for (size_t i = 0; i < path.size(); ++i) {
-        cerr << path[i] << endl;
+        if (verbose) {
+            cout << "[" << path[i] << "]";
+        } else {
+            cout << path[i] << endl;
+        }
     }
+
+    if (verbose) cout << endl;
 }
 
-#ifdef HAVE_OPENDIR
-
 void
 enumeratePlugins()
 {
-    cerr << endl << "Vamp plugin libraries found in search path:" << endl;
-    vector<string> path = Vamp::PluginHostAdapter::getPluginPath();
-    for (size_t i = 0; i < path.size(); ++i) {
-        cerr << "\n" << path[i] << ":" << endl;
-        DIR *d = opendir(path[i].c_str());
-        if (!d) {
-            perror("Failed to open directory");
-            continue;
+    PluginLoader *loader = PluginLoader::getInstance();
+
+    cout << "\nVamp plugin libraries found in search path:" << endl;
+
+    std::vector<PluginLoader::PluginKey> plugins = loader->listPlugins();
+    typedef std::multimap<std::string, PluginLoader::PluginKey>
+        LibraryMap;
+    LibraryMap libraryMap;
+
+    for (size_t i = 0; i < plugins.size(); ++i) {
+        std::string path = loader->getLibraryPathForPlugin(plugins[i]);
+        libraryMap.insert(LibraryMap::value_type(path, plugins[i]));
+    }
+
+    std::string prevPath = "";
+    int index = 0;
+
+    for (LibraryMap::iterator i = libraryMap.begin();
+         i != libraryMap.end(); ++i) {
+        
+        std::string path = i->first;
+        PluginLoader::PluginKey key = i->second;
+
+        if (path != prevPath) {
+            prevPath = path;
+            index = 0;
+            cout << "\n  " << path << ":" << endl;
         }
-        struct dirent *e = 0;
-        while ((e = readdir(d))) {
-//            cerr << "reading: " << e->d_name << endl;
-            if (!(e->d_type & DT_REG)) {
-//                cerr << e->d_name << ": not a regular file" << endl;
-                continue;
+
+        Vamp::Plugin *plugin = loader->loadPlugin(key, 48000);
+        if (plugin) {
+
+            char c = char('A' + index);
+            if (c > 'Z') c = char('a' + (index - 26));
+
+            cout << "    [" << c << "] [v"
+                 << plugin->getVampApiVersion() << "] "
+                 << plugin->getName() << ", \""
+                 << plugin->getIdentifier() << "\"" << " ["
+                 << plugin->getMaker() << "]" << endl;
+
+            PluginLoader::PluginCategoryHierarchy category =
+                loader->getPluginCategory(key);
+            if (!category.empty()) {
+                cout << "       ";
+                for (size_t ci = 0; ci < category.size(); ++ci) {
+                    cout << " > " << category[ci];
+                }
+                cout << endl;
             }
-            int len = strlen(e->d_name);
-            if (len < int(strlen(PLUGIN_SUFFIX) + 2) ||
-                e->d_name[len - strlen(PLUGIN_SUFFIX) - 1] != '.' ||
-                strcmp(e->d_name + len - strlen(PLUGIN_SUFFIX), PLUGIN_SUFFIX)) {
-//                cerr << e->d_name << ": not a library file" << endl;
-                continue;
+
+            if (plugin->getDescription() != "") {
+                cout << "        - " << plugin->getDescription() << endl;
             }
-            char *fp = new char[path[i].length() + len + 3];
-            sprintf(fp, "%s/%s", path[i].c_str(), e->d_name);
-            void *handle = DLOPEN(string(fp), RTLD_LAZY);
-            if (handle) {
-                VampGetPluginDescriptorFunction fn =
-                    (VampGetPluginDescriptorFunction)DLSYM
-                    (handle, "vampGetPluginDescriptor");
-                if (fn) {
-                    cerr << "\n  " << e->d_name << ":" << endl;
-                    int index = 0;
-                    const VampPluginDescriptor *descriptor = 0;
-                    while ((descriptor = fn(VAMP_API_VERSION, index))) {
-                        Vamp::PluginHostAdapter plugin(descriptor, 48000);
-                        char c = char('A' + index);
-                        if (c > 'Z') c = char('a' + (index - 26));
-                        cerr << "    [" << c << "] [v"
-                             << plugin.getVampApiVersion() << "] "
-                             << plugin.getName()
-                             << ", \"" << plugin.getIdentifier() << "\""
-                             << " [" << plugin.getMaker()
-                             << "]" << endl;
-                        if (plugin.getDescription() != "") {
-                            cerr << "        - " << plugin.getDescription() << endl;
-                        }
-                        Vamp::Plugin::OutputList outputs =
-                            plugin.getOutputDescriptors();
-                        if (outputs.size() > 1) {
-                            for (size_t j = 0; j < outputs.size(); ++j) {
-                                cerr << "         (" << j << ") "
-                                     << outputs[j].name
-                                     << ", \"" << outputs[j].identifier << "\""
-                                     << endl;
-                                if (outputs[j].description != "") {
-                                    cerr << "             - " 
-                                         << outputs[j].description << endl;
-                                }
-                            }
-                        }
-                        ++index;
+
+            Vamp::Plugin::OutputList outputs =
+                plugin->getOutputDescriptors();
+
+            if (outputs.size() > 1) {
+                for (size_t j = 0; j < outputs.size(); ++j) {
+                    cout << "         (" << j << ") "
+                         << outputs[j].name << ", \""
+                         << outputs[j].identifier << "\"" << endl;
+                    if (outputs[j].description != "") {
+                        cout << "             - " 
+                             << outputs[j].description << endl;
                     }
-                } else {
-//                    cerr << e->d_name << ": no Vamp descriptor function" << endl;
                 }
-                DLCLOSE(handle);
-            } else {
-                cerr << "\n" << e->d_name << ": unable to load library (" << DLERROR() << ")" << endl;
-            }                
+            }
+
+            ++index;
+
+            delete plugin;
         }
-        closedir(d);
     }
-    cerr << endl;
+
+    cout << endl;
 }
 
-#endif
-
-
 void
 printFeatures(int frame, int sr, int output, Vamp::Plugin::FeatureSet features)
 {
@@ -468,149 +410,5 @@
     }
 }
 
-void
-transformInput(float *buffer, size_t size)
-{
-    double *inbuf = new double[size * 2];
-    double *outbuf = new double[size * 2];
-
-    // Copy across with Hanning window
-    for (size_t i = 0; i < size; ++i) {
-        inbuf[i] = double(buffer[i]) * (0.50 - 0.50 * cos(2 * M_PI * i / size));
-        inbuf[i + size] = 0.0;
-    }
-    
-    for (size_t i = 0; i < size/2; ++i) {
-        double temp = inbuf[i];
-        inbuf[i] = inbuf[i + size/2];
-        inbuf[i + size/2] = temp;
-    }
-
-    fft(size, false, inbuf, inbuf + size, outbuf, outbuf + size);
-
-    for (size_t i = 0; i <= size/2; ++i) {
-        buffer[i * 2] = outbuf[i];
-        buffer[i * 2 + 1] = outbuf[i + size];
-    }
-    
-    delete[] inbuf;
-    delete[] outbuf;
-}
-
-void
-fft(unsigned int n, bool inverse, double *ri, double *ii, double *ro, double *io)
-{
-    if (!ri || !ro || !io) return;
-
-    unsigned int bits;
-    unsigned int i, j, k, m;
-    unsigned int blockSize, blockEnd;
-
-    double tr, ti;
-
-    if (n < 2) return;
-    if (n & (n-1)) return;
-
-    double angle = 2.0 * M_PI;
-    if (inverse) angle = -angle;
-
-    for (i = 0; ; ++i) {
-	if (n & (1 << i)) {
-	    bits = i;
-	    break;
-	}
-    }
-
-    static unsigned int tableSize = 0;
-    static int *table = 0;
-
-    if (tableSize != n) {
-
-	delete[] table;
-
-	table = new int[n];
-
-	for (i = 0; i < n; ++i) {
-	
-	    m = i;
-
-	    for (j = k = 0; j < bits; ++j) {
-		k = (k << 1) | (m & 1);
-		m >>= 1;
-	    }
-
-	    table[i] = k;
-	}
-
-	tableSize = n;
-    }
-
-    if (ii) {
-	for (i = 0; i < n; ++i) {
-	    ro[table[i]] = ri[i];
-	    io[table[i]] = ii[i];
-	}
-    } else {
-	for (i = 0; i < n; ++i) {
-	    ro[table[i]] = ri[i];
-	    io[table[i]] = 0.0;
-	}
-    }
-
-    blockEnd = 1;
-
-    for (blockSize = 2; blockSize <= n; blockSize <<= 1) {
-
-	double delta = angle / (double)blockSize;
-	double sm2 = -sin(-2 * delta);
-	double sm1 = -sin(-delta);
-	double cm2 = cos(-2 * delta);
-	double cm1 = cos(-delta);
-	double w = 2 * cm1;
-	double ar[3], ai[3];
-
-	for (i = 0; i < n; i += blockSize) {
-
-	    ar[2] = cm2;
-	    ar[1] = cm1;
-
-	    ai[2] = sm2;
-	    ai[1] = sm1;
-
-	    for (j = i, m = 0; m < blockEnd; j++, m++) {
-
-		ar[0] = w * ar[1] - ar[2];
-		ar[2] = ar[1];
-		ar[1] = ar[0];
-
-		ai[0] = w * ai[1] - ai[2];
-		ai[2] = ai[1];
-		ai[1] = ai[0];
-
-		k = j + blockEnd;
-		tr = ar[0] * ro[k] - ai[0] * io[k];
-		ti = ar[0] * io[k] + ai[0] * ro[k];
-
-		ro[k] = ro[j] - tr;
-		io[k] = io[j] - ti;
-
-		ro[j] += tr;
-		io[j] += ti;
-	    }
-	}
-
-	blockEnd = blockSize;
-    }
-
-    if (inverse) {
-
-	double denom = (double)n;
-
-	for (i = 0; i < n; i++) {
-	    ro[i] /= denom;
-	    io[i] /= denom;
-	}
-    }
-}