Commit 3001660b authored by Leander Schulten's avatar Leander Schulten

Aubio: Use aubio and not AudioFFT to generate a spectrum/frequency domain...

Aubio: Use aubio and not AudioFFT to generate a spectrum/frequency domain analysis. Remove AudioFFT from the Lichtsteuerung
parent a014e441
Pipeline #204566 passed with stage
in 5 minutes and 14 seconds
......@@ -36,10 +36,7 @@ Die Lichtsteuerung hängt von ein paar anderen Projekten ab.
Boost wird benötigt, um bei Modules nicht lineare Codeausführung zu ermöglichen (Corotines) und wird genutzt, um Stacktraces auszugeben.
#### [RtAudio](https://github.com/thestk/rtaudio)
RtAudio (Realtime Audio) ist eine Bibliothek, mit welcher auf jedem Betriebsystem alle Audioeingänge aufgenommen werden können. Unter Windows ist es auch möglich den Audio Ausgang aufzunehmen. Vor RtAudio wurde diese Aufgabe von der [Capture_Windows_SoundOutput](https://git.rwth-aachen.de/leander.schulten/Capture_Windows_SoundOutput) lib übernommen (Diese konnte nur unter Windows den Standardausgang aufnehmen).
#### [AudioFFT](https://git.rwth-aachen.de/leander.schulten/FFT_for_Audio)
Dieses Projekt ermöglicht es, den abgefangenen Sound auf Frequenzbereiche aufzuspalten, wobei jedem Frequenzbereich eine "Energie"/Stärke zugeordnet wird. Dieses Projekt hängt wiederum von [fftw](http://www.fftw.org/) ab. Diese Abhängigkeiten befinden sich auch hier als kompilierte lib im git.
RtAudio (Realtime Audio) ist eine Bibliothek, mit welcher auf jedem Betriebsystem alle Audioeingänge aufgenommen werden können. Unter Windows ist es auch möglich den Audio Ausgang aufzunehmen. Vor RtAudio wurde diese Aufgabe von der [Capture_Windows_SoundOutput](https://git.rwth-aachen.de/leander.schulten/Capture_Windows_SoundOutput) lib übernommen (Diese konnte nur unter Windows den Standardausgang aufnehmen).
#### [SusbDmx-Driver](https://git.rwth-aachen.de/leander.schulten/SusbDMX-Driver)
Dieses Projekt enthält den aktuellen Treiber, der es ermöglicht, den USB zu DMX Konverter anzusteuern. Dieser Treiber befindet sich nicht als lib hier im git.
......
......@@ -55,12 +55,6 @@ fi
# copy aubio
cp "src/lib/aubio/lib/libaubio-5.dll" "$target_folder"
#copy AudioFFT
cp "src/lib/AudioFFT/dll/win${bit}/AudioFFT.dll" "$target_folder"
cp "src/lib/AudioFFT/dll/win${bit}/libfftw3-3.dll" "$target_folder"
cp "src/lib/AudioFFT/dll/win${bit}/libfftw3f-3.dll" "$target_folder"
cp "src/lib/AudioFFT/dll/win${bit}/libfftw3l-3.dll" "$target_folder"
#copy DrMinGw
if [[ $bit == "64" ]]; then
for file in src/lib/DrMinGW/bin/*; do cp "$file" "$target_folder";done
......
......@@ -20,6 +20,7 @@ SOURCES += \
applicationdata.cpp \
audio/aubio/aubiocapi.cpp \
audio/aubio/onsetanalysis.cpp \
audio/aubio/spectrumanalysis.cpp \
audio/aubio/tempoanalysis.cpp \
audio/audioeventdata.cpp \
audio/remotevolume.cpp \
......@@ -107,6 +108,7 @@ DEFINES += _USE_MATH_DEFINES
HEADERS += \
audio/aubio/aubiocapi.h \
audio/aubio/onsetanalysis.h \
audio/aubio/spectrumanalysis.h \
audio/aubio/tempoanalysis.h \
audio/audioeventdata.h \
audio/remotevolume.h \
......@@ -226,23 +228,6 @@ macx{
INCLUDEPATH += /usr/local/include
}
macx{
#AudioFFT
LIBS += -L$$PWD/'lib/AudioFFT/dll' -lAudioFFT
INCLUDEPATH += $$PWD/lib/AudioFFT/include
}
win32-g++{
#AudioFFT
#LIBS += -L$$PWD/'lib/AudioFFT/dll' -lAudioFFT
contains(QT_ARCH, i386){ # 32 bit
LIBS += -L$$PWD/'lib/AudioFFT/dll/win32/' -lAudioFFT
} else { # 64 bit
LIBS += -L$$PWD/'lib/AudioFFT/dll/win64' -lAudioFFT
}
INCLUDEPATH += $$PWD/'lib/AudioFFT/include'
}
win32-g++{
#DrMinGW
#LIBS += -L$$PWD/'lib/AudioFFT/dll' -lAudioFFT
......@@ -279,12 +264,6 @@ macx{
DEFINES += _GNU_SOURCE
}
win32-msvc{
#AudioFFT
LIBS += -L$$PWD/'lib/AudioFFT/dll/AudioFFT.dll'
INCLUDEPATH += $$PWD/'lib/AudioFFT/include'
}
# RTAudio
INCLUDEPATH += $$PWD/lib/RtAudio/include
LIBS += -L$$PWD/lib/RtAudio/lib -lrtaudio
......
#include "spectrumanalysis.h"
namespace Audio::Aubio {
using namespace C_API;
SpectrumAnalysis::SpectrumAnalysis(C_API::uint_t spectrumSize, C_API::uint_t stepSize) : spectrumAnalyser(new_aubio_pvoc(spectrumSize * 2, stepSize), del_aubio_pvoc), fftOutputData(new_cvec(spectrumSize * 2), del_cvec), inputData{stepSize, nullptr} {}
void SpectrumAnalysis::processNewSamples(float *newSamples) {
inputData.data = newSamples;
aubio_pvoc_do(spectrumAnalyser.get(), &inputData, fftOutputData.get());
}
boost::beast::span<float> SpectrumAnalysis::getSpectrum() const {
return {fftOutputData->norm, fftOutputData->length};
}
float *SpectrumAnalysis::getPointerToSpectrum() const {
return fftOutputData->norm;
}
} // namespace Audio::Aubio
#ifndef SPECTRUMANALYSIS_H
#define SPECTRUMANALYSIS_H
#include "aubiocapi.h"
#include <boost/beast/core/span.hpp> // TODO use std::span in c++20
#include <memory>
namespace Audio::Aubio {
/**
* @brief The SpectrumAnalysis class computes a spectrum (energy for every frequency) for the audio data.
*/
class SpectrumAnalysis {
std::unique_ptr<C_API::aubio_pvoc_t, decltype(&C_API::del_aubio_pvoc)> spectrumAnalyser;
std::unique_ptr<C_API::cvec_t, decltype(&C_API::del_cvec)> fftOutputData;
C_API::fvec_t inputData;
public:
/**
* @brief SpectrumAnalysis Creates a spectrum analysis.
* @param spectrumSize The size of blocks in the spectrum from 0 to sampleRate/2. Must be a power of 2.
* @param stepSize The size of a new block that gets passed to this->processNewSamples().
*/
SpectrumAnalysis(C_API::uint_t spectrumSize, C_API::uint_t stepSize);
/**
* @brief processNewSamples process and analyse new samples
* @param newSamples A pointer to the new samples, the length of the array must be minimun the step size from the constructor
*/
void processNewSamples(float *newSamples);
/**
* @brief getSpectrum returns the spectrum (the enery for every block)
* @return the spectrum
*/
[[nodiscard]] boost::beast::span<float> getSpectrum() const;
/**
* @brief getPointerToSpectrum See getSpectrum().
* @return A pointer to the spectrum. You can modify the values. They will be overwritten in the processNewSamples(float*) method
*/
[[nodiscard]] float *getPointerToSpectrum() const; // remove when using std::span in c++20
};
} // namespace Audio::Aubio
#endif // SPECTRUMANALYSIS_H
......@@ -16,8 +16,8 @@
#endif
namespace Audio {
AudioCaptureManager::AudioCaptureManager():audiofft(sample.size())
{
AudioCaptureManager::AudioCaptureManager() {
rtAudio.showWarnings();
updateCaptureDeviceList();
}
......@@ -35,6 +35,7 @@ void AudioCaptureManager::initCallback(int channels, int samplesPerSecond) {
if (GUI::Colorplot::getLast()) {
GUI::Colorplot::getLast()->setBlockSize(512);
}
spectrumAnalysis.emplace(2048, samplesPerFrame);
}
void AudioCaptureManager::dataCallback(float* data, unsigned int frames, bool*done){
......@@ -58,7 +59,6 @@ void AudioCaptureManager::dataCallback(float* data, unsigned int frames, bool*do
sample.addData(data,data+frames*static_cast<unsigned>(channels),channels-1,firstIndex);
audiofft.analyse(sample.data(),1,fftoutput.data());
{
// feed the *analysis classes with new samples
int restFrames = static_cast<int>(frames);
......@@ -75,6 +75,7 @@ void AudioCaptureManager::dataCallback(float* data, unsigned int frames, bool*do
restFrames -= samplesPerFrame;
continue;
}
spectrumAnalysis->processNewSamples(sample.data() + sample.size() - restFrames);
for (auto &[onsetFunction, pair] : onsetAnalyzes) {
bool wasOnset = pair.first.processNewSamples(sample.data() + sample.size() - restFrames);
pair.second.addOnsetData(pair.second.getNewestSample(), pair.first.getOnsetValue(), 0);
......@@ -95,15 +96,16 @@ void AudioCaptureManager::dataCallback(float* data, unsigned int frames, bool*do
}
}
// db scale
std::transform(fftoutput.begin(), fftoutput.end(), fftoutput.begin(), [](auto i) { return 10 * std::log10(1 + i); });
auto spectrum = spectrumAnalysis->getSpectrum();
std::transform(spectrum.cbegin(), spectrum.cend(), spectrumAnalysis->getPointerToSpectrum(), [](auto i) { return 10 * std::log10(1 + i); });
if (GUI::Graph::getLast() && run) {
GUI::Graph::getLast()->showData(fftoutput.data(), fftoutput.size());
GUI::Graph::getLast()->showData(spectrumAnalysis->getPointerToSpectrum(), spectrum.size());
}
if (GUI::Colorplot::getLast() && run) {
GUI::Colorplot::getLast()->startBlock();
for (int i = 0; i < 512; ++i) {
GUI::Colorplot::getLast()->pushDataToBlock(fftoutput.at(i));
GUI::Colorplot::getLast()->pushDataToBlock(spectrum.begin()[i]);
}
GUI::Colorplot::getLast()->endBlock();
}
......
......@@ -5,9 +5,10 @@
#include "modelvector.h"
#include "sample.h"
#include "aubio/onsetanalysis.h"
#include "aubio/spectrumanalysis.h"
#include "aubio/tempoanalysis.h"
#include "audio_fft.h"
#include <RtAudio.h>
#include <boost/beast/core/span.hpp> // TODO use std::span in c++20
#include <map>
#include <thread>
......@@ -35,12 +36,12 @@ class AudioCaptureManager : public QObject
Q_PROPERTY(int currentCaptureDevice READ getCurrentCaptureDevice WRITE setCurrentCaptureDevice NOTIFY currentCaptureDeviceChanged)
Q_PROPERTY(QAbstractItemModel *captureDeviceNames READ getCaptureDeviceNamesModel CONSTANT)
Sample<float,4096> sample;
std::array<float, 2048> fftoutput;
std::atomic_bool run;
int currentCaptureDevice = -1;
RtAudio rtAudio;
AudioFFT audiofft;
ModelVector<QString> captureDeviceNames;
// we use a optional to delay the creation of the object until we know the samplesPerFrame value
std::optional<Aubio::SpectrumAnalysis> spectrumAnalysis;
int channels = -1;
int samplesPerSecond = -1;
......@@ -105,7 +106,7 @@ public:
*/
const std::vector<QString> &getCaptureDeviceNames() const { return captureDeviceNames.getVector(); }
const std::array<float, 2048> &getFFTOutput() { return fftoutput; }
boost::beast::span<float> getFFTOutput() { return (spectrumAnalysis ? spectrumAnalysis->getSpectrum() : boost::beast::span<float>{nullptr, 0}); }
/**
* @brief requestTempoAnalysis requests the data series from a tempo analysis that uses a spezific onset detection function
* You can call the function with the same parameters multiple times, the result will be the same
......
libAudioFFT.1.0.0.dylib
\ No newline at end of file
libAudioFFT.1.0.0.dylib
\ No newline at end of file
libAudioFFT.1.0.0.dylib
\ No newline at end of file
#ifndef AUDIO_FFT_H
#define AUDIO_FFT_H
#include "audio_fft_global.h"
#include "fftw3.h"
class AUDIO_FFT_SHARED_EXPORT AudioFFT
{
fftw_plan plan;
fftw_complex *in, *out;
const unsigned int size;
public:
AudioFFT(const unsigned int size);
void execute();
void analyse(float* floatData,const int stepsToNext, float*output);
void fillInputData(float* floatData,const int stepsToNext);
void fillInputDataAndApplyHannWindow(float* floatData,const int stepsToNext);
fftw_complex * getInput(){return in;}
fftw_complex * getOutput(){return out;}
/**
* @brief fillOutput füllt size/2 mem positionen mit dem Ergebnis der Analyse in log db scale
* @param mem Ein size/2 langer float array der mit dem Ergebnis gefüllt wird
*/
void fillOutput(float * mem);
unsigned int getSize(){return size;}
~AudioFFT();
private:
void createPlan();
inline float hann(int n);
};
#endif // AUDIO_FFT_H
#ifndef AUDIO_FFT_GLOBAL_H
#define AUDIO_FFT_GLOBAL_H
#include <QtCore/qglobal.h>
#if defined(AUDIO_FFT_LIBRARY)
# define AUDIO_FFT_SHARED_EXPORT Q_DECL_EXPORT
#else
# define AUDIO_FFT_SHARED_EXPORT Q_DECL_IMPORT
#endif
#endif // AUDIO_FFT_GLOBAL_H
/*
* Copyright (c) 2003, 2007-14 Matteo Frigo
* Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology
*
* The following statement of license applies *only* to this header file,
* and *not* to the other files distributed with FFTW or derived therefrom:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/***************************** NOTE TO USERS *********************************
*
* THIS IS A HEADER FILE, NOT A MANUAL
*
* If you want to know how to use FFTW, please read the manual,
* online at http://www.fftw.org/doc/ and also included with FFTW.
* For a quick start, see the manual's tutorial section.
*
* (Reading header files to learn how to use a library is a habit
* stemming from code lacking a proper manual. Arguably, it's a
* *bad* habit in most cases, because header files can contain
* interfaces that are not part of the public, stable API.)
*
****************************************************************************/
#ifndef FFTW3_H
#define FFTW3_H
#include <stdio.h>
#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */
/* If <complex.h> is included, use the C99 complex type. Otherwise
define a type bit-compatible with C99 complex */
#if !defined(FFTW_NO_Complex) && defined(_Complex_I) && defined(complex) && defined(I)
# define FFTW_DEFINE_COMPLEX(R, C) typedef R _Complex C
#else
# define FFTW_DEFINE_COMPLEX(R, C) typedef R C[2]
#endif
#define FFTW_CONCAT(prefix, name) prefix ## name
#define FFTW_MANGLE_DOUBLE(name) FFTW_CONCAT(fftw_, name)
#define FFTW_MANGLE_FLOAT(name) FFTW_CONCAT(fftwf_, name)
#define FFTW_MANGLE_LONG_DOUBLE(name) FFTW_CONCAT(fftwl_, name)
#define FFTW_MANGLE_QUAD(name) FFTW_CONCAT(fftwq_, name)
/* IMPORTANT: for Windows compilers, you should add a line
*/
#define FFTW_DLL
/*
here and in kernel/ifftw.h if you are compiling/using FFTW as a
DLL, in order to do the proper importing/exporting, or
alternatively compile with -DFFTW_DLL or the equivalent
command-line flag. This is not necessary under MinGW/Cygwin, where
libtool does the imports/exports automatically. */
#if defined(FFTW_DLL) && (defined(_WIN32) || defined(__WIN32__))
/* annoying Windows syntax for shared-library declarations */
# if defined(COMPILING_FFTW) /* defined in api.h when compiling FFTW */
# define FFTW_EXTERN extern __declspec(dllexport)
# else /* user is calling FFTW; import symbol */
# define FFTW_EXTERN extern __declspec(dllimport)
# endif
#else
# define FFTW_EXTERN extern
#endif
enum fftw_r2r_kind_do_not_use_me {
FFTW_R2HC=0, FFTW_HC2R=1, FFTW_DHT=2,
FFTW_REDFT00=3, FFTW_REDFT01=4, FFTW_REDFT10=5, FFTW_REDFT11=6,
FFTW_RODFT00=7, FFTW_RODFT01=8, FFTW_RODFT10=9, FFTW_RODFT11=10
};
struct fftw_iodim_do_not_use_me {
int n; /* dimension size */
int is; /* input stride */
int os; /* output stride */
};
#include <stddef.h> /* for ptrdiff_t */
struct fftw_iodim64_do_not_use_me {
ptrdiff_t n; /* dimension size */
ptrdiff_t is; /* input stride */
ptrdiff_t os; /* output stride */
};
typedef void (*fftw_write_char_func_do_not_use_me)(char c, void *);
typedef int (*fftw_read_char_func_do_not_use_me)(void *);
/*
huge second-order macro that defines prototypes for all API
functions. We expand this macro for each supported precision
X: name-mangling macro
R: real data type
C: complex data type
*/
#define FFTW_DEFINE_API(X, R, C) \
\
FFTW_DEFINE_COMPLEX(R, C); \
\
typedef struct X(plan_s) *X(plan); \
\
typedef struct fftw_iodim_do_not_use_me X(iodim); \
typedef struct fftw_iodim64_do_not_use_me X(iodim64); \
\
typedef enum fftw_r2r_kind_do_not_use_me X(r2r_kind); \
\
typedef fftw_write_char_func_do_not_use_me X(write_char_func); \
typedef fftw_read_char_func_do_not_use_me X(read_char_func); \
\
FFTW_EXTERN void X(execute)(const X(plan) p); \
\
FFTW_EXTERN X(plan) X(plan_dft)(int rank, const int *n, \
C *in, C *out, int sign, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_dft_1d)(int n, C *in, C *out, int sign, \
unsigned flags); \
FFTW_EXTERN X(plan) X(plan_dft_2d)(int n0, int n1, \
C *in, C *out, int sign, unsigned flags); \
FFTW_EXTERN X(plan) X(plan_dft_3d)(int n0, int n1, int n2, \
C *in, C *out, int sign, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_many_dft)(int rank, const int *n, \
int howmany, \
C *in, const int *inembed, \
int istride, int idist, \
C *out, const int *onembed, \
int ostride, int odist, \
int sign, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_guru_dft)(int rank, const X(iodim) *dims, \
int howmany_rank, \
const X(iodim) *howmany_dims, \
C *in, C *out, \
int sign, unsigned flags); \
FFTW_EXTERN X(plan) X(plan_guru_split_dft)(int rank, const X(iodim) *dims, \
int howmany_rank, \
const X(iodim) *howmany_dims, \
R *ri, R *ii, R *ro, R *io, \
unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_guru64_dft)(int rank, \
const X(iodim64) *dims, \
int howmany_rank, \
const X(iodim64) *howmany_dims, \
C *in, C *out, \
int sign, unsigned flags); \
FFTW_EXTERN X(plan) X(plan_guru64_split_dft)(int rank, \
const X(iodim64) *dims, \
int howmany_rank, \
const X(iodim64) *howmany_dims, \
R *ri, R *ii, R *ro, R *io, \
unsigned flags); \
\
FFTW_EXTERN void X(execute_dft)(const X(plan) p, C *in, C *out); \
FFTW_EXTERN void X(execute_split_dft)(const X(plan) p, R *ri, R *ii, \
R *ro, R *io); \
\
FFTW_EXTERN X(plan) X(plan_many_dft_r2c)(int rank, const int *n, \
int howmany, \
R *in, const int *inembed, \
int istride, int idist, \
C *out, const int *onembed, \
int ostride, int odist, \
unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_dft_r2c)(int rank, const int *n, \
R *in, C *out, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_dft_r2c_1d)(int n,R *in,C *out,unsigned flags); \
FFTW_EXTERN X(plan) X(plan_dft_r2c_2d)(int n0, int n1, \
R *in, C *out, unsigned flags); \
FFTW_EXTERN X(plan) X(plan_dft_r2c_3d)(int n0, int n1, \
int n2, \
R *in, C *out, unsigned flags); \
\
\
FFTW_EXTERN X(plan) X(plan_many_dft_c2r)(int rank, const int *n, \
int howmany, \
C *in, const int *inembed, \
int istride, int idist, \
R *out, const int *onembed, \
int ostride, int odist, \
unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_dft_c2r)(int rank, const int *n, \
C *in, R *out, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_dft_c2r_1d)(int n,C *in,R *out,unsigned flags); \
FFTW_EXTERN X(plan) X(plan_dft_c2r_2d)(int n0, int n1, \
C *in, R *out, unsigned flags); \
FFTW_EXTERN X(plan) X(plan_dft_c2r_3d)(int n0, int n1, \
int n2, \
C *in, R *out, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_guru_dft_r2c)(int rank, const X(iodim) *dims, \
int howmany_rank, \
const X(iodim) *howmany_dims, \
R *in, C *out, \
unsigned flags); \
FFTW_EXTERN X(plan) X(plan_guru_dft_c2r)(int rank, const X(iodim) *dims, \
int howmany_rank, \
const X(iodim) *howmany_dims, \
C *in, R *out, \
unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_guru_split_dft_r2c)( \
int rank, const X(iodim) *dims, \
int howmany_rank, \
const X(iodim) *howmany_dims, \
R *in, R *ro, R *io, \
unsigned flags); \
FFTW_EXTERN X(plan) X(plan_guru_split_dft_c2r)( \
int rank, const X(iodim) *dims, \
int howmany_rank, \
const X(iodim) *howmany_dims, \
R *ri, R *ii, R *out, \
unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_guru64_dft_r2c)(int rank, \
const X(iodim64) *dims, \
int howmany_rank, \
const X(iodim64) *howmany_dims, \
R *in, C *out, \
unsigned flags); \
FFTW_EXTERN X(plan) X(plan_guru64_dft_c2r)(int rank, \
const X(iodim64) *dims, \
int howmany_rank, \
const X(iodim64) *howmany_dims, \
C *in, R *out, \
unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_guru64_split_dft_r2c)( \
int rank, const X(iodim64) *dims, \
int howmany_rank, \
const X(iodim64) *howmany_dims, \
R *in, R *ro, R *io, \
unsigned flags); \
FFTW_EXTERN X(plan) X(plan_guru64_split_dft_c2r)( \
int rank, const X(iodim64) *dims, \
int howmany_rank, \
const X(iodim64) *howmany_dims, \
R *ri, R *ii, R *out, \
unsigned flags); \
\
FFTW_EXTERN void X(execute_dft_r2c)(const X(plan) p, R *in, C *out); \
FFTW_EXTERN void X(execute_dft_c2r)(const X(plan) p, C *in, R *out); \
\
FFTW_EXTERN void X(execute_split_dft_r2c)(const X(plan) p, \
R *in, R *ro, R *io); \
FFTW_EXTERN void X(execute_split_dft_c2r)(const X(plan) p, \
R *ri, R *ii, R *out); \
\
FFTW_EXTERN X(plan) X(plan_many_r2r)(int rank, const int *n, \
int howmany, \
R *in, const int *inembed, \
int istride, int idist, \
R *out, const int *onembed, \
int ostride, int odist, \
const X(r2r_kind) *kind, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_r2r)(int rank, const int *n, R *in, R *out, \
const X(r2r_kind) *kind, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_r2r_1d)(int n, R *in, R *out, \
X(r2r_kind) kind, unsigned flags); \
FFTW_EXTERN X(plan) X(plan_r2r_2d)(int n0, int n1, R *in, R *out, \
X(r2r_kind) kind0, X(r2r_kind) kind1, \
unsigned flags); \
FFTW_EXTERN X(plan) X(plan_r2r_3d)(int n0, int n1, int n2, \
R *in, R *out, X(r2r_kind) kind0, \
X(r2r_kind) kind1, X(r2r_kind) kind2, \
unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_guru_r2r)(int rank, const X(iodim) *dims, \
int howmany_rank, \
const X(iodim) *howmany_dims, \
R *in, R *out, \
const X(r2r_kind) *kind, unsigned flags); \
\
FFTW_EXTERN X(plan) X(plan_guru64_r2r)(int rank, const X(iodim64) *dims, \
int howmany_rank, \
const X(iodim64) *howmany_dims, \
R *in, R *out, \
const X(r2r_kind) *kind, unsigned flags); \
\
FFTW_EXTERN void X(execute_r2r)(const X(plan) p, R *in, R *out); \
\
FFTW_EXTERN void X(destroy_plan)(X(plan) p); \
FFTW_EXTERN void X(forget_wisdom)(void); \
FFTW_EXTERN void X(cleanup)(void); \
\
FFTW_EXTERN void X(set_timelimit)(double t); \
\
FFTW_EXTERN void X(plan_with_nthreads)(int nthreads); \
FFTW_EXTERN int X(init_threads)(void); \
FFTW_EXTERN void X(cleanup_threads)(void); \