summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIOhannes m zmölnig <zmoelnig@umlautS.umlaeute.mur.at>2021-01-20 09:10:34 +0100
committerIOhannes m zmölnig <zmoelnig@umlautS.umlaeute.mur.at>2021-01-20 09:10:34 +0100
commit6acadc7e322d4be0e696efd0ad7719be9f66abe9 (patch)
tree157923cb8752b4de6f8f46c1462bda3ffa2d9be8 /src
parent9ddd3730560abd20b2eed088a0b8a2fc53b31816 (diff)
New upstream version 1.3.0+ds0
Diffstat (limited to 'src')
-rw-r--r--src/AudioInterface.cpp223
-rw-r--r--src/AudioInterface.h38
-rw-r--r--src/AudioTester.cpp195
-rw-r--r--src/AudioTester.h220
-rw-r--r--src/Compressor.cpp57
-rw-r--r--src/Compressor.h148
-rw-r--r--src/CompressorPresets.h81
-rw-r--r--src/DataProtocol.cpp2
-rw-r--r--src/DataProtocol.h6
-rw-r--r--src/Effects.h571
-rw-r--r--src/JMess.cpp23
-rw-r--r--src/JackAudioInterface.cpp37
-rw-r--r--src/JackAudioInterface.h8
-rw-r--r--src/JackTrip.cpp541
-rw-r--r--src/JackTrip.h122
-rw-r--r--src/JackTripThread.cpp6
-rw-r--r--src/JackTripWorker.cpp42
-rw-r--r--src/JackTripWorker.h33
-rw-r--r--src/JitterBuffer.cpp389
-rw-r--r--src/JitterBuffer.h90
-rw-r--r--src/Limiter.cpp71
-rw-r--r--src/Limiter.h179
-rw-r--r--src/PacketHeader.cpp10
-rw-r--r--src/PacketHeader.h2
-rw-r--r--src/ProcessPlugin.h18
-rw-r--r--src/Reverb.cpp70
-rw-r--r--src/Reverb.h158
-rw-r--r--src/RingBuffer.cpp159
-rw-r--r--src/RingBuffer.h55
-rw-r--r--src/Settings.cpp764
-rw-r--r--src/Settings.h43
-rw-r--r--src/UdpDataProtocol.cpp278
-rw-r--r--src/UdpDataProtocol.h39
-rw-r--r--src/UdpHubListener.cpp338
-rw-r--r--src/UdpHubListener.h58
-rwxr-xr-xsrc/build4
-rw-r--r--src/compressordsp.h1816
-rw-r--r--src/freeverbdsp.h2168
-rw-r--r--src/freeverbmonodsp.h2154
-rw-r--r--src/jacktrip.pro27
-rw-r--r--src/jacktrip_globals.cpp1
-rw-r--r--src/jacktrip_globals.h3
-rw-r--r--src/jacktrip_main.cpp152
-rw-r--r--src/jacktrip_types_alt.h7
-rw-r--r--src/limiterdsp.h1751
-rwxr-xr-xsrc/makeXcodeproj.sh1
-rw-r--r--src/zitarevdsp.h2375
-rw-r--r--src/zitarevmonodsp.h2357
48 files changed, 16920 insertions, 970 deletions
diff --git a/src/AudioInterface.cpp b/src/AudioInterface.cpp
index 06fe59e..8caf348 100644
--- a/src/AudioInterface.cpp
+++ b/src/AudioInterface.cpp
@@ -39,6 +39,7 @@
#include "JackTrip.h"
#include <iostream>
#include <cmath>
+#include <assert.h>
using std::cout; using std::endl;
@@ -57,7 +58,7 @@ AudioInterface::AudioInterface(JackTrip* jacktrip,
mAudioBitResolution(AudioBitResolution*8),
mBitResolutionMode(AudioBitResolution),
mSampleRate(gDefaultSampleRate), mBufferSizeInSamples(gDefaultBufferSizeInSamples),
- mInputPacket(NULL), mOutputPacket(NULL)
+ mInputPacket(NULL), mOutputPacket(NULL), mLoopBack(false), mProcessingAudio(false)
{
#ifndef WAIR
//cc
@@ -85,6 +86,11 @@ AudioInterface::AudioInterface(JackTrip* jacktrip,
mAPInBuffer[i] = NULL;
}
#endif // endwhere
+
+ mInBufCopy.resize(mNumInChans);
+ for (int i=0; i<mNumInChans; i++) {
+ mInBufCopy[i] = new sample_t[MAX_AUDIO_BUFFER_SIZE]; // required for processing audio input
+ }
}
@@ -93,7 +99,7 @@ AudioInterface::~AudioInterface()
{
delete[] mInputPacket;
delete[] mOutputPacket;
-#ifndef WAIR // WAIR
+#ifndef WAIR // NOT WAIR:
for (int i = 0; i < mNumInChans; i++) {
delete[] mInProcessBuffer[i];
}
@@ -115,6 +121,16 @@ AudioInterface::~AudioInterface()
delete[] mAPInBuffer[i];
}
#endif // endwhere
+
+ for (int i = 0; i < mProcessPluginsFromNetwork.size(); i++) {
+ delete mProcessPluginsFromNetwork[i];
+ }
+ for (int i = 0; i < mProcessPluginsToNetwork.size(); i++) {
+ delete mProcessPluginsToNetwork[i];
+ }
+ for (int i=0; i<mNumInChans; i++) {
+ delete mInBufCopy[i];
+ }
}
@@ -153,7 +169,7 @@ void AudioInterface::setup()
int nframes = getBufferSizeInSamples();
-#ifndef WAIR // WAIR
+#ifndef WAIR // NOT WAIR:
for (int i = 0; i < mNumInChans; i++) {
mInProcessBuffer[i] = new sample_t[nframes];
// set memory to 0
@@ -208,8 +224,8 @@ void AudioInterface::callback(QVarLengthArray<sample_t*>& in_buffer,
// ----------------------------------
#ifdef WAIR // WAIR
- // qDebug() << "--" << mProcessPlugins.size();
- bool client = (mProcessPlugins.size() == 2);
+ // qDebug() << "--" << mProcessPluginsFromNetwork.size();
+ bool client = (mProcessPluginsFromNetwork.size() == 2);
#define COMBDSP 1 // client
#define APDSP 0 // client
#define DCBDSP 0 // server
@@ -218,7 +234,18 @@ void AudioInterface::callback(QVarLengthArray<sample_t*>& in_buffer,
}
#endif // endwhere
+ // ==== RECEIVE AUDIO CHANNELS FROM NETWORK ====
computeProcessFromNetwork(out_buffer, n_frames);
+ // =============================================
+
+ // out_buffer is from the network and goes "out" to local audio
+ // hardware via JACK:
+
+ // mAudioTesterP will be nullptr for hub server's JackTripWorker instances
+ if (mAudioTesterP && mAudioTesterP->getEnabled()) {
+ mAudioTesterP->lookForReturnPulse(out_buffer, n_frames);
+ }
+
#ifdef WAIR // WAIR
// nib16 result now in mNetInBuffer
#endif // endwhere
@@ -229,19 +256,14 @@ void AudioInterface::callback(QVarLengthArray<sample_t*>& in_buffer,
/// \todo Implement for more than one process plugin, now it just works propertely with one.
/// do it chaining outputs to inputs in the buffers. May need a tempo buffer
-#ifndef WAIR // WAIR
- for (int i = 0; i < mNumInChans; i++) {
- std::memset(mInProcessBuffer[i], 0, sizeof(sample_t) * n_frames);
- std::memcpy(mInProcessBuffer[i], out_buffer[i], sizeof(sample_t) * n_frames);
+#ifndef WAIR // NOT WAIR:
+ for (int i = 0; i < mProcessPluginsFromNetwork.size(); i++) {
+ ProcessPlugin* p = mProcessPluginsFromNetwork[i];
+ if (p->getInited()) {
+ p->compute(n_frames, out_buffer.data(), out_buffer.data());
+ }
}
- for (int i = 0; i < mNumOutChans; i++) {
- std::memset(mOutProcessBuffer[i], 0, sizeof(sample_t) * n_frames);
- }
-
- for (int i = 0; i < mProcessPlugins.size(); i++) {
- mProcessPlugins[i]->compute(n_frames, mInProcessBuffer.data(), mOutProcessBuffer.data());
- }
-#else // WAIR
+#else // WAIR:
for (int i = 0; i < ((mNumNetRevChans)?mNumNetRevChans:mNumOutChans); i++) {
std::memset(mOutProcessBuffer[i], 0, sizeof(sample_t) * n_frames);
}
@@ -257,14 +279,44 @@ void AudioInterface::callback(QVarLengthArray<sample_t*>& in_buffer,
}
// nib16 to cib16
- if (mNumNetRevChans && client) mProcessPlugins[COMBDSP]->compute(n_frames,
- mInProcessBuffer.data(), mOutProcessBuffer.data());
+ if (mNumNetRevChans && client) {
+ mProcessPluginsFromNetwork[COMBDSP]->compute(n_frames, mInProcessBuffer.data(), mOutProcessBuffer.data());
+ }
// compute cob16
#endif // endwhere
- // 3) Finally, send packets to peer
- // --------------------------------
- computeProcessToNetwork(in_buffer, n_frames);
+ // 3) Send packets to network:
+ // mAudioTesterP will be nullptr for hub server's JackTripWorker instances:
+ bool audioTesting = (mAudioTesterP && mAudioTesterP->getEnabled());
+ int nop = mProcessPluginsToNetwork.size(); // number of OUTGOING processing modules
+ if (nop>0 || audioTesting) { // cannot modify in_buffer, so make a copy
+ // in_buffer is "in" from local audio hardware via JACK
+ if (mInBufCopy.size() < mNumInChans) { // created in constructor above
+ std::cerr << "*** AudioInterface.cpp: Number of Input Channels changed - insufficient room reserved\n";
+ exit(1);
+ }
+ if (MAX_AUDIO_BUFFER_SIZE < n_frames) { // allocated in constructor above
+ std::cerr << "*** AudioInterface.cpp: n_frames = " << n_frames
+ << " larger than expected max = " << MAX_AUDIO_BUFFER_SIZE << "\n";
+ exit(1);
+ }
+ for (int i=0; i<mNumInChans; i++) {
+ std::memcpy(mInBufCopy[i], in_buffer[i], sizeof(sample_t) * n_frames);
+ }
+ for (int i = 0; i < nop; i++) {
+ // process all outgoing channels with ProcessPlugins:
+ ProcessPlugin* p = mProcessPluginsToNetwork[i];
+ if (p->getInited()) {
+ p->compute(n_frames, mInBufCopy.data(), mInBufCopy.data());
+ }
+ }
+ if (audioTesting) {
+ mAudioTesterP->writeImpulse(mInBufCopy, n_frames); // writes last channel of mInBufCopy with test impulse
+ }
+ computeProcessToNetwork(mInBufCopy, n_frames);
+ } else { // copy saved if no plugins and no audio testing in progress:
+ computeProcessToNetwork(in_buffer, n_frames); // send processed input audio to network - OUTGOING
+ }
#ifdef WAIR // WAIR
// aib2 + cob16 to nob16
@@ -302,7 +354,7 @@ void AudioInterface::callback(QVarLengthArray<sample_t*>& in_buffer,
for (int i = 0; i < mNumOutChans; i++) {
std::memset(out_buffer[i], 0, sizeof(sample_t) * n_frames);
}
- mProcessPlugins[APDSP]->compute(n_frames, mAPInBuffer.data(), out_buffer.data());
+ mProcessPluginsFromNetwork[APDSP]->compute(n_frames, mAPInBuffer.data(), out_buffer.data());
// compute ap2 into aob2
//#define ADD_DIRECT
@@ -319,8 +371,7 @@ void AudioInterface::callback(QVarLengthArray<sample_t*>& in_buffer,
}
#endif // endwhere
-
- ///************PROTORYPE FOR CELT**************************
+ ///************PROTOTYPE FOR CELT**************************
///********************************************************
/*
CELTMode* mode;
@@ -337,6 +388,28 @@ void AudioInterface::callback(QVarLengthArray<sample_t*>& in_buffer,
}
+//*******************************************************************************
+void AudioInterface::broadcastCallback(QVarLengthArray<sample_t*>& mon_buffer,
+ unsigned int n_frames)
+{
+ /// \todo cast *mInBuffer[i] to the bit resolution
+ // Output Process (from NETWORK to JACK)
+ // ----------------------------------------------------------------
+ // Read Audio buffer from RingBuffer (read from incoming packets)
+ mJackTrip->receiveBroadcastPacket(mOutputPacket);
+ // Extract separate channels to send to Jack
+ for (int i = 0; i < mNumOutChans; i++) {
+ sample_t* tmp_sample = mon_buffer[i]; //sample buffer for channel i
+ for (unsigned int j = 0; j < n_frames; j++) {
+ // Change the bit resolution on each sample
+ fromBitToSampleConversion(
+ // use interleaved channel layout
+ //&mOutputPacket[(i*mSizeInBytesPerChannel) + (j*mBitResolutionMode)],
+ &mOutputPacket[(j*mBitResolutionMode*mNumOutChans) + (i*mBitResolutionMode)],
+ &tmp_sample[j], mBitResolutionMode );
+ }
+ }
+}
//*******************************************************************************
// Before sending and reading to Jack, we have to round to the sample resolution
@@ -359,7 +432,9 @@ void AudioInterface::computeProcessFromNetwork(QVarLengthArray<sample_t*>& out_b
for (unsigned int j = 0; j < n_frames; j++) {
// Change the bit resolution on each sample
fromBitToSampleConversion(
- &mOutputPacket[(i*mSizeInBytesPerChannel) + (j*mBitResolutionMode)],
+ // use interleaved channel layout
+ //&mOutputPacket[(i*mSizeInBytesPerChannel) + (j*mBitResolutionMode)],
+ &mOutputPacket[(j*mBitResolutionMode*mNumOutChans) + (i*mBitResolutionMode)],
&tmp_sample[j], mBitResolutionMode );
}
}
@@ -371,13 +446,15 @@ void AudioInterface::computeProcessFromNetwork(QVarLengthArray<sample_t*>& out_b
//--------
// This should be faster for 32 bits
//std::memcpy(mOutBuffer[i], &mOutputPacket[i*mSizeInBytesPerChannel],
- // mSizeInBytesPerChannel);
+ // mSizeInBytesPerChannel);
//--------
sample_t* tmp_sample = out_buffer[i]; //sample buffer for channel i
for (unsigned int j = 0; j < n_frames; j++) {
// Change the bit resolution on each sample
fromBitToSampleConversion(
- &mOutputPacket[(i*mSizeInBytesPerChannel) + (j*mBitResolutionMode)],
+ // use interleaved channel layout
+ //&mOutputPacket[(i*mSizeInBytesPerChannel) + (j*mBitResolutionMode)],
+ &mOutputPacket[(j*mBitResolutionMode*mNumOutChans) + (i*mBitResolutionMode)],
&tmp_sample[j], mBitResolutionMode );
}
}
@@ -406,7 +483,9 @@ void AudioInterface::computeProcessToNetwork(QVarLengthArray<sample_t*>& in_buff
tmp_result = INGAIN*tmp_sample[j] + COMBGAIN*tmp_process_sample[j];
fromSampleToBitConversion(
&tmp_result,
- &mInputPacket[(i*mSizeInBytesPerChannel) + (j*mBitResolutionMode)],
+ // use interleaved channel layout
+ //&mInputPacket[(i*mSizeInBytesPerChannel) + (j*mBitResolutionMode)],
+ &mInputPacket[(j*mBitResolutionMode*mNumOutChans) + (i*mBitResolutionMode)],
mBitResolutionMode );
}
}
@@ -417,7 +496,7 @@ void AudioInterface::computeProcessToNetwork(QVarLengthArray<sample_t*>& in_buff
//--------
// This should be faster for 32 bits
//std::memcpy(&mInputPacket[i*mSizeInBytesPerChannel], mInBuffer[i],
- // mSizeInBytesPerChannel);
+ // mSizeInBytesPerChannel);
//--------
sample_t* tmp_sample = in_buffer[i]; //sample buffer for channel i
sample_t* tmp_process_sample = mOutProcessBuffer[i]; //sample buffer from the output process
@@ -428,14 +507,15 @@ void AudioInterface::computeProcessToNetwork(QVarLengthArray<sample_t*>& in_buff
tmp_result = tmp_sample[j] + tmp_process_sample[j];
fromSampleToBitConversion(
&tmp_result,
- &mInputPacket[(i*mSizeInBytesPerChannel) + (j*mBitResolutionMode)],
+ // use interleaved channel layout
+ //&mInputPacket[(i*mSizeInBytesPerChannel) + (j*mBitResolutionMode)],
+ &mInputPacket[(j*mBitResolutionMode*mNumOutChans) + (i*mBitResolutionMode)],
mBitResolutionMode );
}
}
// Send Audio buffer to Network
mJackTrip->sendNetworkPacket( mInputPacket );
-}
-
+} // /computeProcessToNetwork
//*******************************************************************************
// This function quantize from 32 bit to a lower bit resolution
@@ -448,22 +528,23 @@ void AudioInterface::fromSampleToBitConversion
int8_t tmp_8;
uint8_t tmp_u8; // unsigned to quantize the remainder in 24bits
int16_t tmp_16;
- sample_t tmp_sample;
+ double tmp_sample;
sample_t tmp_sample16;
sample_t tmp_sample8;
switch (targetBitResolution)
{
case BIT8 :
// 8bit integer between -128 to 127
- tmp_sample = floor( (*input) * 128.0 ); // 2^7 = 128.0
+ tmp_sample = std::max(-127.0, std::min(127.0, std::round( (*input) * 127.0 ))); // 2^7 = 128
tmp_8 = static_cast<int8_t>(tmp_sample);
std::memcpy(output, &tmp_8, 1); // 8bits = 1 bytes
break;
case BIT16 :
// 16bit integer between -32768 to 32767
- tmp_sample = floor( (*input) * 32768.0 ); // 2^15 = 32768.0
+ // original scaling: tmp_sample = floor( (*input) * 32768.0 ); // 2^15 = 32768.0
+ tmp_sample = std::max(-32767.0, std::min(32767.0, std::round( (*input) * 32767.0 ))); // 2^15 = 32768
tmp_16 = static_cast<int16_t>(tmp_sample);
- std::memcpy(output, &tmp_16, 2); // 16bits = 2 bytes
+ std::memcpy(output, &tmp_16, 2); // 2 bytes output in Little Endian order (LSB -> smallest address)
break;
case BIT24 :
// To convert to 24 bits, we first quantize the number to 16bit
@@ -483,7 +564,10 @@ void AudioInterface::fromSampleToBitConversion
std::memcpy(output+2, &tmp_u8, 1); // 8bits = 1 bytes
break;
case BIT32 :
- std::memcpy(output, input, 4); // 32bit = 4 bytes
+ tmp_sample = *input;
+ // not necessary yet:
+ // tmp_sample = std::max(-1.0, std::min(1.0, tmp_sample));
+ std::memcpy(output, &tmp_sample, 4); // 32bit = 4 bytes
break;
}
}
@@ -532,32 +616,71 @@ void AudioInterface::fromBitToSampleConversion
//*******************************************************************************
-void AudioInterface::appendProcessPlugin(ProcessPlugin* plugin)
+void AudioInterface::appendProcessPluginToNetwork(ProcessPlugin* plugin)
+{
+ if (not plugin) { return; }
+ int nTestChans = (mAudioTesterP && mAudioTesterP->getEnabled()) ? 1 : 0;
+ int nPluginChans = mNumInChans - nTestChans;
+ assert(nTestChans==0 || (mAudioTesterP->getSendChannel() == mNumInChans-1));
+ if (plugin->getNumInputs() < nPluginChans) {
+ std::cerr << "*** AudioInterface.cpp: appendProcessPluginToNetwork: ProcessPlugin "
+ << typeid(plugin).name() << " REJECTED due to having "
+ << plugin->getNumInputs() << " inputs, while the audio to JACK needs "
+ << nPluginChans << " inputs\n";
+ return;
+ }
+ mProcessPluginsToNetwork.append(plugin);
+}
+
+void AudioInterface::appendProcessPluginFromNetwork(ProcessPlugin* plugin)
{
- /// \todo check that channels in ProcessPlugins are less or same that jack channels
- if ( plugin->getNumInputs() ) {}
- mProcessPlugins.append(plugin);
+ if (not plugin) { return; }
+ int nTestChans = (mAudioTesterP && mAudioTesterP->getEnabled()) ? 1 : 0;
+ int nPluginChans = mNumOutChans - nTestChans;
+ assert(nTestChans==0 || (mAudioTesterP->getSendChannel() == mNumOutChans-1));
+ if (plugin->getNumOutputs() > nPluginChans) {
+ std::cerr << "*** AudioInterface.cpp: appendProcessPluginFromNetwork: ProcessPlugin "
+ << typeid(plugin).name() << " REJECTED due to having "
+ << plugin->getNumOutputs() << " inputs, while the JACK audio output requires "
+ << nPluginChans << " outputs\n";
+ return;
+ }
+ mProcessPluginsFromNetwork.append(plugin);
}
+void AudioInterface::initPlugins()
+{
+ int nPlugins = mProcessPluginsFromNetwork.size() + mProcessPluginsToNetwork.size();
+ if (nPlugins > 0) {
+ std::cout << "Initializing Faust plugins (have " << nPlugins
+ << ") at sampling rate " << mSampleRate << "\n";
+ for (ProcessPlugin* plugin : mProcessPluginsFromNetwork) {
+ plugin->init(mSampleRate);
+ }
+ for (ProcessPlugin* plugin : mProcessPluginsToNetwork) {
+ plugin->init(mSampleRate);
+ }
+ }
+}
//*******************************************************************************
AudioInterface::samplingRateT AudioInterface::getSampleRateType() const
{
- uint32_t rate = getSampleRate();
+ int32_t rate = getSampleRate();
- if ( rate == 22050 ) {
+ if ( 100 > qAbs(rate - 22050) ) {
return AudioInterface::SR22; }
- else if ( rate == 32000 ) {
+ else if ( 100 > qAbs(rate - 32000) ) {
return AudioInterface::SR32; }
- else if ( rate == 44100 ) {
+ else if ( 100 > qAbs(rate - 44100) ) {
return AudioInterface::SR44; }
- else if ( rate == 48000 ) {
+ else if ( 100 > qAbs(rate - 48000) ) {
return AudioInterface::SR48; }
- else if ( rate == 88200 ) {
+ else if ( 100 > qAbs(rate - 88200) ) {
return AudioInterface::SR88; }
- else if ( rate == 96000 ) {
+ else if ( 100 > qAbs(rate - 96000) ) {
return AudioInterface::SR96; }
- else if ( rate == 19200 ) {
+ else if ( 100 > qAbs(rate - 19200) ) {
return AudioInterface::SR192; }
return AudioInterface::UNDEF;
diff --git a/src/AudioInterface.h b/src/AudioInterface.h
index c4b953c..f5089eb 100644
--- a/src/AudioInterface.h
+++ b/src/AudioInterface.h
@@ -40,6 +40,7 @@
#include "ProcessPlugin.h"
#include "jacktrip_types.h"
+#include "AudioTester.h"
#include <QVarLengthArray>
#include <QVector>
@@ -115,16 +116,33 @@ public:
* \param in_buffer Array of output audio samplers for each channel. The user
* is reponsible to check that each channel has n_frames samplers
*/
+ virtual void broadcastCallback(QVarLengthArray<sample_t*>& mon_buffer,
+ unsigned int n_frames);
virtual void callback(QVarLengthArray<sample_t*>& in_buffer,
QVarLengthArray<sample_t*>& out_buffer,
unsigned int n_frames);
- /** \brief Append a ProcessPlugin. The order of processing is determined by
- * the order by which appending is done.
- * \param plugin a ProcesPlugin smart pointer. Create the object instance
+ /** \brief appendProcessPluginToNetwork(): Append a ProcessPlugin for outgoing audio.
+ * The processing order equals order they were appended.
+ * This processing is in the JackTrip client before sending to the network.
+ * \param plugin a ProcessPlugin smart pointer. Create the object instance
* using something like:\n
* <tt>std::tr1::shared_ptr<ProcessPluginName> loopback(new ProcessPluginName);</tt>
*/
- virtual void appendProcessPlugin(ProcessPlugin* plugin);
+ virtual void appendProcessPluginToNetwork(ProcessPlugin* plugin);
+ /** \brief appendProcessPluginFromNetwork():
+ * Same as appendProcessPluginToNetwork() except that these plugins operate
+ * on the audio received from the network (typically from a JackTrip server).
+ * The complete processing chain then looks like this:
+ * audio -> JACK -> JackTrip client -> processPlugin to network
+ * -> remote JackTrip server
+ * -> JackTrip client -> processPlugin from network -> JACK -> audio
+ */
+ virtual void appendProcessPluginFromNetwork(ProcessPlugin* plugin);
+ /** \brief initPlugins():
+ * Initialize all ProcessPlugin modules.
+ * The audio sampling rate (mSampleRate) must be set at this time.
+ */
+ void initPlugins();
virtual void connectDefaultPorts() = 0;
/** \brief Convert a 32bit number (sample_t) into one of the bit resolution
* supported (audioBitResolutionT).
@@ -160,6 +178,9 @@ public:
{ mBufferSizeInSamples = buf_size; }
/// \brief Set Client Name to something different that the default (JackTrip)
virtual void setClientName(QString ClientName) = 0;
+ virtual void setLoopBack(bool b) { mLoopBack = b; }
+ virtual void enableBroadcastOutput() {}
+ virtual void setAudioTesterP(AudioTester* atp) { mAudioTesterP = atp; }
//------------------------------------------------------------------
//--------------GETTERS---------------------------------------------
@@ -209,17 +230,24 @@ private:
QVarLengthArray<sample_t*> mNetInBuffer; ///< Vector of Input buffers/channel read from net
QVarLengthArray<sample_t*> mAPInBuffer; ///< Vector of Input buffers/channel for AllPass input
#endif // endwhere
+ QVarLengthArray<sample_t*> mInBufCopy; ///< needed in callback() to modify JACK audio input
int mAudioBitResolution; ///< Bit resolution in audio samples
AudioInterface::audioBitResolutionT mBitResolutionMode; ///< Bit resolution (audioBitResolutionT) mode
uint32_t mSampleRate; ///< Sampling Rate
uint32_t mDeviceID; ///< RTAudio DeviceID
uint32_t mBufferSizeInSamples; ///< Buffer size in samples
size_t mSizeInBytesPerChannel; ///< Size in bytes per audio channel
- QVector<ProcessPlugin*> mProcessPlugins; ///< Vector of ProcesPlugin<EM>s</EM>
+ QVector<ProcessPlugin*> mProcessPluginsFromNetwork; ///< Vector of ProcessPlugin<EM>s</EM>
+ QVector<ProcessPlugin*> mProcessPluginsToNetwork; ///< Vector of ProcessPlugin<EM>s</EM>
QVarLengthArray<sample_t*> mInProcessBuffer;///< Vector of Input buffers/channel for ProcessPlugin
QVarLengthArray<sample_t*> mOutProcessBuffer;///< Vector of Output buffers/channel for ProcessPlugin
int8_t* mInputPacket; ///< Packet containing all the channels to read from the RingBuffer
int8_t* mOutputPacket; ///< Packet containing all the channels to send to the RingBuffer
+ bool mLoopBack;
+ AudioTester* mAudioTesterP { nullptr };
+protected:
+ bool mProcessingAudio; ///< Set when processing an audio callback buffer pair
+ const uint32_t MAX_AUDIO_BUFFER_SIZE = 8192;
};
#endif // __AUDIOINTERFACE_H__
diff --git a/src/AudioTester.cpp b/src/AudioTester.cpp
new file mode 100644
index 0000000..136c1d4
--- /dev/null
+++ b/src/AudioTester.cpp
@@ -0,0 +1,195 @@
+//*****************************************************************
+/*
+ JackTrip: A System for High-Quality Audio Network Performance
+ over the Internet
+
+ Copyright (c) 2020 Julius Smith, Juan-Pablo Caceres, Chris Chafe.
+ SoundWIRE group at CCRMA, Stanford University.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+*/
+//*****************************************************************
+
+/**
+ * \file AudioTester.cpp
+ * \author Julius Smith
+ * \license MIT
+ * \date Aug-Oct 2020
+ */
+
+#include "AudioTester.h"
+#include <assert.h>
+
+// Called 1st in Audiointerface.cpp
+void AudioTester::lookForReturnPulse(QVarLengthArray<sample_t*>& out_buffer,
+ unsigned int n_frames) {
+ if (not enabled) {
+ std::cerr << "*** AudioTester.h: lookForReturnPulse: NOT ENABLED\n";
+ return;
+ }
+ if (impulsePending) { // look for return impulse in channel sendChannel:
+ assert(sendChannel<out_buffer.size());
+ for (uint n=0; n<n_frames; n++) {
+ float amp = out_buffer[sendChannel][n];
+ if (amp > 0.5 * ampCellHeight) { // got something
+ int cellNum = getImpulseCellNum(out_buffer[sendChannel][n]);
+ if (cellNum != pendingCell) { // not our impulse!
+ std::cerr <<
+ "*** AudioTester.h: computeProcessFromNetwork: Received pulse amplitude "
+ << amp << " (cell " << cellNum << ") while looking for cell "
+ << pendingCell << "\n";
+
+ if (cellNum > pendingCell) { // we missed it
+ std::cerr << " - ABORTING CURRENT PULSE\n";
+ impulsePending = false;
+ } else { // somehow we got the previous pulse again - repeated packet or underrun-caused repetition (old buffer)
+ std::cerr << " - IGNORING FOUND PULSE WAITING FURTHER\n";
+ }
+ } else { // found our impulse:
+ int64_t elapsedSamples = -1;
+ if (n >= n_frames-1) {
+ // Impulse timestamp didn't make it so we skip this one.
+ } else {
+ float sampleCountWhenImpulseSent = - 32768.0f * out_buffer[sendChannel][n+1];
+ elapsedSamples = sampleCountSinceImpulse + n - int64_t(sampleCountWhenImpulseSent);
+ sampleCountSinceImpulse = 1; // reset sample counter between impulses
+ roundTripCount += 1.0;
+ }
+ // int64_t curTimeUS = timeMicroSec(); // time since launch in us
+ // int64_t impulseDelayUS = curTimeUS - ImpulseTimeUS;
+ // float impulseDelaySec = float(impulseDelayUS) * 1.0e-6;
+ // float impulseDelayBuffers = impulseDelaySec / (float(n_frames)/float(sampleRate));
+ // int64_t impulseDelayMS = (int64_t)round(double(impulseDelayUS)/1000.0);
+ if (elapsedSamples > 0) { // found impulse and reset, time to print buffer results:
+ double elapsedSamplesMS = 1000.0 * double(elapsedSamples)/double(sampleRate); // ms
+ extendLatencyHistogram(elapsedSamplesMS);
+ if (roundTripCount > 1.0) {
+ double prevSum = roundTripMean * (roundTripCount-1.0); // undo previous normalization
+ roundTripMean = (prevSum + elapsedSamplesMS) / roundTripCount; // add latest and renormalize
+ double prevSumSq = roundTripMeanSquare * (roundTripCount-1.0); // undo previous normalization
+ roundTripMeanSquare = (prevSumSq + elapsedSamplesMS*elapsedSamplesMS) / roundTripCount;
+ } else { // just getting started:
+ roundTripMean = elapsedSamplesMS;
+ roundTripMeanSquare = elapsedSamplesMS * elapsedSamplesMS;
+ }
+ if (roundTripCount == 1.0) {
+ printf("JackTrip Test Mode (option -x printIntervalInSeconds=%0.3f)\n",printIntervalSec);
+ printf("\tA test impulse-train is output on channel %d (from 0) with repeatedly ramping amplitude\n",
+ sendChannel);
+ if (printIntervalSec == 0.0) {
+ printf("\tPrinting each audio buffer round-trip latency in ms followed by cumulative (mean and [standard deviation])");
+ } else {
+ printf("\tPrinting cumulative mean and [standard deviation] of audio round-trip latency in ms");
+ printf(" every %0.3f seconds", printIntervalSec);
+ }
+ printf(" after skipping first %d buffers:\n", bufferSkipStart);
+ // not printing this presently: printf("( * means buffer skipped due missing timestamp or lost impulse)\n");
+ lastPrintTimeUS = timeMicroSec();
+ }
+ //printf("%d (%d) ", elapsedSamplesMS, impulseDelayMS); // measured time is "buffer time" not sample time
+ int64_t curTimeUS = timeMicroSec(); // time since launch in us
+ double timeSinceLastPrintUS = double(curTimeUS - lastPrintTimeUS);
+ double stdDev = sqrt(std::max(0.0, (roundTripMeanSquare - (roundTripMean*roundTripMean))));
+ if (timeSinceLastPrintUS >= printIntervalSec * 1.0e6) {
+ if (printIntervalSec == 0.0) { printf("%0.1f (", elapsedSamplesMS); }
+ printf("%0.1f [%0.1f]", roundTripMean, stdDev);
+ if (printIntervalSec == 0.0) { printf(") "); } else { printf(" "); }
+ lastPrintTimeUS = curTimeUS;
+ if (printIntervalSec >= 1.0) { // print histogram
+ std::cout << "\n" << getLatencyHistogramString() << "\n";
+ }
+ }
+ std::cout << std::flush;
+ } else {
+ // not printing this presently: printf("* "); // we got the impulse but lost its timestamp in samples
+ }
+ impulsePending = false;
+ } // found our impulse
+ // remain pending until timeout, hoping to find our return pulse
+ } // got something
+ } // loop over samples
+ sampleCountSinceImpulse += n_frames; // gets reset to 1 when impulse is found, counts freely until then
+ } // ImpulsePending
+}
+
+// Called 2nd in Audiointerface.cpp
+void AudioTester::writeImpulse(QVarLengthArray<sample_t*>& mInBufCopy,
+ unsigned int n_frames) {
+ if (not enabled) {
+ std::cerr << "*** AudioTester.h: writeImpulse: NOT ENABLED\n";
+ return;
+ }
+ if (bufferSkip <= 0) { // send test signals (-x option)
+ bool sendImpulse;
+ if (impulsePending) {
+ sendImpulse = false; // unless:
+ const uint64_t timeOut = 500e3; // time out after waiting 500 ms
+ if (timeMicroSec() > (impulseTimeUS + timeOut)) {
+ sendImpulse = true;
+ std::cout << "\n*** Audio Latency Test (-x): TIMED OUT waiting for return impulse *** sending a new one\n";
+ }
+ } else { // time for the next repeating impulse:
+ sendImpulse = true;
+ }
+ if (sendImpulse) {
+ assert(sendChannel < mInBufCopy.size());
+ mInBufCopy[sendChannel][0] = getImpulseAmp();
+ for (uint n=1; n<n_frames; n++) {
+ mInBufCopy[sendChannel][n] = 0;
+ }
+ impulsePending = true;
+ impulseTimeUS = timeMicroSec();
+ impulseTimeSamples = sampleCountSinceImpulse; // timer in samples for current impulse loopback test
+ // Also send impulse time:
+ if (n_frames>1) { // always true?
+ mInBufCopy[sendChannel][1] = -float(impulseTimeSamples)/32768.0f; // survives if there is no digital processing at the server
+ } else {
+ std::cerr << "\n*** AudioTester.h: Timestamp cannot fit into a lenth " << n_frames << " buffer ***\n";
+ }
+ } else {
+ mInBufCopy[sendChannel][0] = 0.0f; // send zeros until a new impulse is needed
+ if (n_frames>1) {
+ mInBufCopy[sendChannel][1] = 0.0f;
+ }
+ }
+ } else {
+ bufferSkip--;
+ }
+}
+
+void AudioTester::printHelp(char* command, [[maybe_unused]] char helpCase) {
+ std::cout << "HELP for \"" << command << " printIntervalSec\" // (end-of-line comments start with `//'):\n";
+ std::cout << "\n";
+ std::cout << "Print roundtrip audio delay statistics for the highest-numbered audio channel every printIntervalSec seconds,\n";
+ std::cout << "including an ASCII latency histogram if printIntervalSec is 1.0 or more.\n";
+ std::cout << "\n";
+ std::cout << "A test impulse is sent to the server in the last audio channel,\n";
+ std::cout << " the number of samples until it returns is measured, and this repeats.\n";
+ std::cout << "The jacktrip server must provide audio loopback (e.g., -p4).\n";
+ std::cout << "The cumulative mean and standard-deviation (\"statistics\") are computed for the measured loopback times,\n";
+ std::cout << " and printed every printIntervalSec seconds.\n";
+ std::cout << "If printIntervalSec is zero, the roundtrip-time and statistics in milliseconds are printed for each individual impulse.\n";
+ std::cout << "If printIntervalSec is positive, statistics are printed after each print interval, with no individual measurements.\n";
+ std::cout << "If printIntervalSec is 1.0 or larger, a cumulative histogram of all impulse roundtrip-times is printed as well.\n";
+ std::cout << "The first 100 audio buffers are skipped in order to measure only steady-state network-audio-delay performance.\n";
+ std::cout << "Lower audio channels are not affected, enabling latency measurement and display during normal operation.\n";
+}
diff --git a/src/AudioTester.h b/src/AudioTester.h
new file mode 100644
index 0000000..4a08f78
--- /dev/null
+++ b/src/AudioTester.h
@@ -0,0 +1,220 @@
+//*****************************************************************
+/*
+ JackTrip: A System for High-Quality Audio Network Performance
+ over the Internet
+
+ Copyright (c) 2020 Julius Smith, Juan-Pablo Caceres, Chris Chafe.
+ SoundWIRE group at CCRMA, Stanford University.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+*/
+//*****************************************************************
+
+/**
+ * \file AudioTester.h
+ * \author Julius Smith
+ * \license MIT
+ * \date Aug-Oct 2020
+ */
+
+#pragma once
+
+#include "jacktrip_types.h" // sample_t
+
+#include <iostream>
+//#include <ctime>
+#include <chrono>
+#include <cstdint>
+#include <cmath>
+#include <string>
+#include <map>
+
+#include <QVarLengthArray>
+
+class AudioTester
+{
+ bool enabled { false };
+ float printIntervalSec { 1.0f };
+ int sendChannel { 0 };
+
+ bool impulsePending { false };
+ int64_t lastPrintTimeUS { 0 };
+ int64_t impulseTimeUS { 0 };
+ int64_t impulseTimeSamples { 0 };
+ uint64_t sampleCountSinceImpulse { 1 }; // 0 not used
+ double roundTripMean { 0.0 };
+ double roundTripMeanSquare { 0.0 };
+ double roundTripCount { 0.0 };
+ const int bufferSkipStart { 100 };
+ int bufferSkip { bufferSkipStart };
+ const float impulseAmplitude { 0.1f };
+ const int numAmpCells { 10 };
+ const float ampCellHeight { impulseAmplitude/numAmpCells };
+
+ const double latencyHistogramCellWidth { 5.0 }; // latency range in ms covered one cell
+ const double latencyHistogramCellMin { 0.0 };
+ const double latencyHistogramCellMax { 19.0 }; // in cells, so 5x this is max latency in ms
+ const int latencyHistogramPrintCountMax { 72 }; // normalize when asterisks exceed this number
+
+ int pendingCell { 0 }; // 0 is not used
+ float sampleRate { 48000.0f };
+
+public:
+ AudioTester() {}
+ ~AudioTester() = default;
+
+ void lookForReturnPulse(QVarLengthArray<sample_t*>& out_buffer,
+ unsigned int n_frames);
+
+ void writeImpulse(QVarLengthArray<sample_t*>& mInBufCopy,
+ unsigned int n_frames);
+
+ bool getEnabled() { return enabled; }
+ void setEnabled(bool e) { enabled = e; }
+ void setPrintIntervalSec(float s) { printIntervalSec = s; }
+ void setSendChannel(int c) { sendChannel = c; }
+ int getSendChannel() { return sendChannel; }
+ int getPendingCell() { return pendingCell; }
+ void setPendingCell(int pc) { pendingCell = pc; }
+ void setSampleRate(float fs) { sampleRate = fs; }
+ int getBufferSkip() { return bufferSkip; } // used for debugging breakpoints
+ void printHelp(char* command, char helpCase);
+
+private:
+
+ float getImpulseAmp() {
+ pendingCell += 1; // only called when no impulse is pending
+ if (pendingCell >= numAmpCells) {
+ pendingCell = 1; // wrap-around, not using zero
+ }
+ float imp = float(pendingCell) * (impulseAmplitude/float(numAmpCells));
+ return imp;
+ }
+
+ int getImpulseCellNum(float amp) {
+ float ch = ampCellHeight;
+ float cell = amp / ch;
+ int iCell = int(std::floor(0.5f + cell));
+ if (iCell > numAmpCells - 1) {
+ std::cerr << "*** AudioTester.h: getImpulseCellNum("<<amp<<"): Return pulse amplitude is beyond maximum expected\n";
+ iCell = numAmpCells-1;
+ } else if (iCell < 0) {
+ std::cerr << "*** AudioTester.h: getImpulseCellNum("<<amp<<"): Return pulse amplitude is below minimum expected\n";
+ iCell = 0;
+ }
+ return iCell;
+ }
+
+ uint64_t timeMicroSec() {
+#if 1
+ using namespace std::chrono;
+ // return duration_cast<milliseconds>(system_clock::now().time_since_epoch()).count();
+ return duration_cast<microseconds>(high_resolution_clock::now().time_since_epoch()).count();
+#else
+ clock_t tics_since_launch = std::clock();
+ double timeUS = double(tics_since_launch)/double(CLOCKS_PER_SEC);
+ return (uint64_t)timeUS;
+#endif
+ }
+
+ std::map<int, int> latencyHistogram;
+
+ std::map<int, int> getLatencyHistogram() {
+ return latencyHistogram;
+ }
+
+ void extendLatencyHistogram(double latencyMS) {
+ int latencyCell = static_cast<int>(floor(std::max(latencyHistogramCellMin,
+ std::min(latencyHistogramCellMax,
+ std::floor(latencyMS / latencyHistogramCellWidth)))));
+ latencyHistogram[latencyCell] += 1;
+ }
+
+ int latencyHistogramCountMax() {
+ int lhMax = 0;
+ int histStart = latencyHistogramFirstNonzeroCellIndex();
+ int histLast = latencyHistogramLastNonzeroCellIndex();
+ for (int i = histStart; i <= histLast; ++i) {
+ int lhi = latencyHistogram[i];
+ if (lhi > lhMax) {
+ lhMax = lhi;
+ }
+ }
+ return lhMax;
+ }
+
+ int latencyHistogramFirstNonzeroCellIndex() {
+ for (int i=latencyHistogramCellMin; i <= latencyHistogramCellMax; i++) {
+ if (latencyHistogram[i]>0) {
+ return i;
+ }
+ }
+ std::cerr << "*** AudioTester: LATENCY HISTOGRAM IS EMPTY!\n";
+ return -1;
+ }
+
+ int latencyHistogramLastNonzeroCellIndex() {
+ for (int i=latencyHistogramCellMax; i>=latencyHistogramCellMin; i--) {
+ if (latencyHistogram[i]>0) {
+ return i;
+ }
+ }
+ std::cerr << "*** AudioTester: LATENCY HISTOGRAM IS EMPTY!\n";
+ return -1;
+ }
+
+ std::string getLatencyHistogramString() {
+ int histStart = latencyHistogramFirstNonzeroCellIndex();
+ int histLast = latencyHistogramLastNonzeroCellIndex();
+ std::string marker = "*";
+ double histScale = 1.0;
+ int lhcm = latencyHistogramCountMax();
+ int lhpcm = latencyHistogramPrintCountMax;
+ bool normalizing = lhpcm < lhcm;
+ if (normalizing) {
+ marker = "#";
+ histScale = double(lhpcm) / double(lhcm);
+ }
+ std::string rows = "";
+ for (int i = histStart; i <= histLast; ++i) {
+ int hi = latencyHistogram[i];
+ int hin = int(std::round(histScale * double(hi)));
+ std::string istrm1 = std::to_string(int(latencyHistogramCellWidth * double(i)));
+ std::string istr = std::to_string(int(latencyHistogramCellWidth * double(i+1)));
+ // std::string histr = boost::format("%02d",hi);
+ std::string histr = std::to_string(hi);
+ while (histr.length()<3) {
+ histr = " " + histr;
+ }
+ std::string row = "["+istrm1+"-"+istr+"ms]="+histr+":";
+ for (int j=0; j<hin; j++) {
+ row += marker;
+ }
+ rows += row + "\n";
+ }
+ if (histLast == latencyHistogramCellMax) {
+ rows += " and above\n";
+ }
+ return rows;
+ }
+
+};
diff --git a/src/Compressor.cpp b/src/Compressor.cpp
new file mode 100644
index 0000000..a1ed346
--- /dev/null
+++ b/src/Compressor.cpp
@@ -0,0 +1,57 @@
+//*****************************************************************
+/*
+ JackTrip: A System for High-Quality Audio Network Performance
+ over the Internet
+
+ Copyright (c) 2020 Julius Smith, Juan-Pablo Caceres, Chris Chafe.
+ SoundWIRE group at CCRMA, Stanford University.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+*/
+//*****************************************************************
+
+/**
+ * \file Compressor.cpp
+ * \author Julius Smith, based on LoopBack.h
+ * \date July 2008
+ */
+
+
+#include "Compressor.h"
+
+#include <iostream>
+
+//*******************************************************************************
+void Compressor::compute(int nframes, float** inputs, float** outputs)
+{
+ if (not inited) {
+ std::cerr << "*** Compressor " << this << ": init never called! Doing it now.\n";
+ if (fSamplingFreq <= 0) {
+ fSamplingFreq = 48000;
+ std::cout << "Compressor " << this << ": *** HAD TO GUESS the sampling rate (chose 48000 Hz) ***\n";
+ }
+ init(fSamplingFreq);
+ }
+ for ( int i = 0; i < mNumChannels; i++ ) {
+ compressorP[i]->compute(nframes, &inputs[i], &outputs[i]);
+ }
+}
diff --git a/src/Compressor.h b/src/Compressor.h
new file mode 100644
index 0000000..d5f41ea
--- /dev/null
+++ b/src/Compressor.h
@@ -0,0 +1,148 @@
+//*****************************************************************
+/*
+ JackTrip: A System for High-Quality Audio Network Performance
+ over the Internet
+
+ Copyright (c) 2020 Julius Smith, Juan-Pablo Caceres, Chris Chafe.
+ SoundWIRE group at CCRMA, Stanford University.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+*/
+//*****************************************************************
+
+/**
+ * \file Compressor.h
+ * \author Julius Smith, starting from Limiter.h
+ * \date August 2020
+ */
+
+
+/** \brief Applies compressor_mono from the faustlibraries distribution, compressors.lib
+ *
+ */
+#ifndef __COMPRESSOR_H__
+#define __COMPRESSOR_H__
+
+#include "ProcessPlugin.h"
+#include "compressordsp.h"
+#include "CompressorPresets.h"
+#include <vector>
+
+/** \brief A Compressor reduces the output dynamic range when the
+ * signal level exceeds the threshold.
+ */
+class Compressor : public ProcessPlugin
+{
+public:
+ /// \brief The class constructor sets the number of audio channels and default parameters.
+ Compressor(int numchans, // xtor
+ bool verboseIn = false,
+ float ratioIn = 2.0f,
+ float thresholdDBIn = -24.0f,
+ float attackMSIn = 15.0f,
+ float releaseMSIn = 40.0f,
+ float makeUpGainDBIn = 2.0f)
+ : mNumChannels(numchans)
+ , ratio(ratioIn)
+ , thresholdDB(thresholdDBIn)
+ , attackMS(attackMSIn)
+ , releaseMS(releaseMSIn)
+ , makeUpGainDB(makeUpGainDBIn)
+ {
+ setVerbose(verboseIn);
+ // presets.push_back(std::make_unique<CompressorPreset>(ratio,thresholdDB,attackMS,releaseMS,makeUpGainDB));
+ for ( int i = 0; i < mNumChannels; i++ ) {
+ compressorP.push_back(new compressordsp);
+ compressorUIP.push_back(new APIUI); // #included in compressordsp.h
+ compressorP[i]->buildUserInterface(compressorUIP[i]);
+ }
+ }
+
+ Compressor(int numchans, // xtor
+ bool verboseIn = false,
+ CompressorPreset preset = CompressorPresets::voice) :
+ Compressor(numchans,verboseIn,
+ preset.ratio,
+ preset.thresholdDB,
+ preset.attackMS,
+ preset.releaseMS,
+ preset.makeUpGainDB)
+ {}
+ /// \brief The class destructor
+ virtual ~Compressor() {
+ for ( int i = 0; i < mNumChannels; i++ ) {
+ delete compressorP[i];
+ delete compressorUIP[i];
+ }
+ compressorP.clear();
+ compressorUIP.clear();
+ }
+
+ // void setParamAllChannels(std::string& pName, float p) {
+ void setParamAllChannels(const char pName[], float p) {
+ for ( int i = 0; i < mNumChannels; i++ ) {
+ int ndx = compressorUIP[i]->getParamIndex(pName);
+ if (ndx >= 0) {
+ compressorUIP[i]->setParamValue(ndx, p);
+ if (verbose) {
+ std::cout << "Compressor.h: parameter " << pName << " set to " << p << " on audio channel " << i << "\n";
+ }
+ } else {
+ std::cerr << "*** Compressor.h: Could not find parameter named " << pName << "\n";
+ }
+ }
+ }
+
+ void init(int samplingRate) override {
+ ProcessPlugin::init(samplingRate);
+ if (samplingRate != fSamplingFreq) {
+ std::cerr << "Sampling rate not set by superclass!\n";
+ std::exit(1); }
+ fs = float(fSamplingFreq);
+ for ( int i = 0; i < mNumChannels; i++ ) {
+ compressorP[i]->init(fs); // compression filter parameters depend on sampling rate
+ }
+ setParamAllChannels("Ratio", ratio);
+ setParamAllChannels("Threshold", thresholdDB);
+ setParamAllChannels("Attack", attackMS);
+ setParamAllChannels("Release", releaseMS);
+ setParamAllChannels("MakeUpGain", makeUpGainDB);
+ inited = true;
+ }
+
+ int getNumInputs() override { return(mNumChannels); }
+ int getNumOutputs() override { return(mNumChannels); }
+ void compute(int nframes, float** inputs, float** outputs) override;
+
+private:
+ float fs;
+ int mNumChannels;
+ std::vector<compressordsp*> compressorP;
+ std::vector<APIUI*> compressorUIP;
+ float ratio;
+ float thresholdDB;
+ float attackMS;
+ float releaseMS;
+ float makeUpGainDB;
+};
+
+#endif
diff --git a/src/CompressorPresets.h b/src/CompressorPresets.h
new file mode 100644
index 0000000..2a12db1
--- /dev/null
+++ b/src/CompressorPresets.h
@@ -0,0 +1,81 @@
+#pragma once
+
+#include <array>
+
+struct CompressorPreset {
+ float ratio;
+ float thresholdDB;
+ float attackMS;
+ float releaseMS;
+ float makeUpGainDB;
+ CompressorPreset(float r, float t, float a, float rel, float m)
+ : ratio(r)
+ , thresholdDB(t)
+ , attackMS(a)
+ , releaseMS(rel)
+ , makeUpGainDB(m)
+ {}
+ ~CompressorPreset() = default;
+};
+
+namespace CompressorPresets
+{
+ // name ratio thresh attack rel mugain
+ const CompressorPreset voice { 2.0f, -24.0f, 15.0f, 40.0f, 2.0f };
+ const CompressorPreset horns { 3.0f, -10.0f, 100.0f, 250.0f, 2.0f };
+ const CompressorPreset snare { 5.0f, -4.0f, 5.0f, 150.0f, 3.0f };
+ const uint numPresets { 3 };
+ const std::array<CompressorPreset,numPresets> standardPresets { voice, horns, snare };
+ enum CompressorPresetNames { CPN_VOICE, CPN_BRASS, CPN_SNARE, CPN_NUMPRESETS };
+}
+
+#if 0 // not yet using this
+// Dynamic extension of CompressorPresets:
+struct CompressorPresetList {
+ std::vector<CompressorPreset*> presets;
+ CompressorPresetList() { // define some standard presets
+ presets.push_back( new CompressorPreset(CompressorPresets::voice) );
+ presets.push_back( new CompressorPreset(CompressorPresets::horns) );
+ presets.push_back( new CompressorPreset(CompressorPresets::snare) );
+ }
+ ~CompressorPresetList() = default;
+};
+#endif
+
+/* Settings from http://www.anythingpeaceful.org/sonar/settings/comp.html
+
+ Name Thresh(dB) Att(ms) Rel(ms) Ratio:1 Gain(dB) Comments
+ Vocal 1 -20 31 342 2.5 2 Compressor for Solo Vocal
+ Vocal 2 -8 26 331 2.5 1.5 Variation of Solo 1
+ Full Comp 1 -8 60 2500 2.5 0 For Overall Volume Level
+ Full Comp 2 -18 94 447 3.5 2.5 Variation of Total Comp 1: Harder ratio
+ Full Comp 3 -16 11 180 6 6 Nearly a limiter effect
+ Kick Comp -24 9 58 3 5.5 Compressor for Acoustic Bass Drum
+ Snare Comp -17 8 12 2.5 3.5 Compressor for Acoustic Snare Drum
+ Guitar -10 5 238 2.5 1.5 Compressor for Acoustic Guitar
+ Brass Sec -18 18 226 1.7 4 Brass Sounds for Strong Attacks
+ Bass 1 -12 15 470 2 4.5 Finger Picked Bass Guitar
+ Bass 2 -12 6 133 1.7 4 Slap Electric Bass
+ E Guitar -8 7 261 3.5 2.5 Electric Guitar Compressor
+ Piano 1 -9 17 238 2.5 1 Brightens Piano
+ Piano 2 -18 7 174 3.5 6 Variation of Piano 1
+ Kick -14 2 35 2 3.5 For sampled Bass Drum
+ Snare -18 8 354 4 8 For sampled Snare Drum
+ Strings 1 -11 33 749 2 1.5 For String instruments
+ Strings 2 -12 93 2500 1.5 1.5 For Violas and Cellos
+ Strings 3 -17 76 186 1.5 2.5 Cellos or DoubleBass
+ Syn Bass -10 9 250 3.5 3 Adjust level of Synth Bass
+ Syn Pad -13 58 238 2 2 Prevents diffusion of sound in synth pad
+ Limiting -1 0.1 325 20 0 Slow release limiter
+ Chorusing -9 39 225 1.7 2.5 For vocal Chorusing
+
+ From https://www.dummies.com/art-center/music/recording-music/dynamic-music-compression-settings-for-horns-piano-and-percussion/
+
+ Horns –8 100 300 2.5-3 2 Brasses not normally compressed [jos gain estimate based on above table]
+ Piano -10 100-105 115 1.5-2 2 Normally not compressed ["]
+ Kick -6 40-50 200-300 4-6 3 Looks more like a limiter to me [jos] ["]
+ Snare -4 5-10 125-175 4-6 3 Crucial for a tight, punchy sound
+ Bongos -6 10-25 100-300 3-6 3 "Hand Drums" - protect against excess "slap"
+ Perc. -10 10-20 50 3-6 3 Transient overdrive protection in mix
+
+*/
diff --git a/src/DataProtocol.cpp b/src/DataProtocol.cpp
index a23120a..aac86eb 100644
--- a/src/DataProtocol.cpp
+++ b/src/DataProtocol.cpp
@@ -52,7 +52,7 @@ using std::cout; using std::endl;
DataProtocol::DataProtocol(JackTrip* jacktrip,
const runModeT runmode,
int /*bind_port*/, int /*peer_port*/) :
- mStopped(false), mHasPacketsToReceive(false), mRunMode(runmode), mJackTrip(jacktrip)
+ mStopped(false), mHasPacketsToReceive(false), mRunMode(runmode), mJackTrip(jacktrip), mUseRtPriority(false)
{}
diff --git a/src/DataProtocol.h b/src/DataProtocol.h
index 413263d..6be9a5a 100644
--- a/src/DataProtocol.h
+++ b/src/DataProtocol.h
@@ -180,11 +180,14 @@ public:
};
virtual bool getStats(PktStat*) {return false;}
+ virtual void setIssueSimulation(double /*loss*/, double /*jitter*/, double /*max_delay*/) {}
+ void setUseRtPriority(bool use) {mUseRtPriority = use;}
+
signals:
void signalError(const char* error_message);
void signalReceivedConnectionFromPeer();
-
+ void signalCeaseTransmission(const QString &reason = "");
protected:
@@ -222,6 +225,7 @@ private:
protected:
//PacketHeader* mHeader; ///< Packet Header
JackTrip* mJackTrip; ///< JackTrip mediator class
+ bool mUseRtPriority;
};
diff --git a/src/Effects.h b/src/Effects.h
new file mode 100644
index 0000000..086d40e
--- /dev/null
+++ b/src/Effects.h
@@ -0,0 +1,571 @@
+//*****************************************************************
+/*
+ JackTrip: A System for High-Quality Audio Network Performance
+ over the Internet
+
+ Copyright (c) 2020 Julius Smith.
+ SoundWIRE group at CCRMA, Stanford University.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+*/
+//*****************************************************************
+
+/**
+ * \file Effects.h
+ * \author Julius Smith
+ * \date Aug 2020
+ */
+
+#pragma once
+
+#include "ProcessPlugin.h"
+#include "Limiter.h"
+#include "Compressor.h"
+#include "CompressorPresets.h"
+#include "Reverb.h"
+#include <assert.h>
+#include <vector>
+
+class Effects
+{
+ int mNumIncomingChans;
+ int mNumOutgoingChans;
+ int gVerboseFlag = 0;
+public:
+ enum LIMITER_MODE {
+ LIMITER_NONE,
+ LIMITER_INCOMING, // from network
+ LIMITER_OUTGOING, // to network
+ LIMITER_BOTH
+ };
+private:
+ LIMITER_MODE mLimit; ///< audio limiter controls
+ unsigned int mNumClientsAssumed; ///< assumed number of clients (audio sources)
+ double limiterWarningAmplitude;
+
+ enum InOrOut { IO_NEITHER, IO_IN, IO_OUT } io;
+ bool inCompressor = false;
+ bool outCompressor = false;
+ bool inZitarev = false;
+ bool outZitarev = false;
+ bool inFreeverb = false;
+ bool outFreeverb = false;
+ bool incomingEffectsAllocated = false;
+ bool outgoingEffectsAllocated = false;
+ Compressor* inCompressorP = nullptr;
+ Compressor* outCompressorP = nullptr;
+ CompressorPreset inCompressorPreset = CompressorPresets::voice; // ./CompressorPresets.h
+ CompressorPreset outCompressorPreset = CompressorPresets::voice;
+ Reverb* inZitarevP = nullptr;
+ Reverb* outZitarevP = nullptr;
+ Reverb* inFreeverbP = nullptr;
+ Reverb* outFreeverbP = nullptr;
+ int parenLevel = 0;
+ char lastEffect = '\0';
+ float zitarevInLevel = 1.0f; // "Level" = wetness from 0 to 1
+ float freeverbInLevel = 1.0f;
+ float zitarevOutLevel = 1.0f;
+ float freeverbOutLevel = 1.0f;
+ float mReverbLevel; // for backward compatibility: 0-1 Freeverb, 1-2 Zitarev
+ Limiter* inLimiterP = nullptr;
+ Limiter* outLimiterP = nullptr;
+
+public:
+
+ Effects(bool outGoingLimiterOn=true) :
+ mNumIncomingChans(2),
+ mNumOutgoingChans(2),
+ mLimit(outGoingLimiterOn ? LIMITER_OUTGOING : LIMITER_NONE),
+ mNumClientsAssumed(2),
+ limiterWarningAmplitude(0.0)
+ {}
+
+ ~Effects() {
+ /*
+ Plugin ownership presently passes to JackTrip,
+ and deletion occurs in AudioInterface.cpp. See
+ delete mProcessPluginsFromNetwork[i];
+ delete mProcessPluginsToNetwork[i];
+ there. If/when we ever do it here:
+ if (inCompressor) { delete inCompressorP; }
+ if (outCompressor) { delete outCompressorP; }
+ if (inZitarev) { delete inZitarevP; }
+ if (outZitarev) { delete outZitarevP; }
+ if (inFreeverb) { delete inFreeverbP; }
+ if (outFreeverb) { delete outFreeverbP; }
+ but if everyone can compile C++11,
+ let's switch to using std::unique_ptr.
+ */
+ }
+
+ unsigned int getNumClientsAssumed() { return mNumClientsAssumed; }
+
+ LIMITER_MODE getLimit() { return mLimit; }
+ void setNoLimiters() { mLimit = LIMITER_NONE; }
+
+ ProcessPlugin* getInCompressor() { return inCompressorP; }
+ ProcessPlugin* getOutCompressor() { return outCompressorP; }
+ ProcessPlugin* getInZitarev() { return inZitarevP; }
+ ProcessPlugin* getOutZitarev() { return outZitarevP; }
+ ProcessPlugin* getInFreeverb() { return inFreeverbP; }
+ ProcessPlugin* getOutFreeverb() { return outFreeverbP; }
+ ProcessPlugin* getInLimiter() { return inLimiterP; }
+ ProcessPlugin* getOutLimiter() { return outLimiterP; }
+
+ bool getHaveEffect() {
+ return
+ inCompressor || outCompressor ||
+ inZitarev || outZitarev ||
+ inFreeverb || outFreeverb ;
+ }
+
+ bool getHaveLimiter() {
+ return mLimit != LIMITER_NONE;
+ }
+
+ void setVerboseFlag(int v) {
+ gVerboseFlag = v;
+ }
+
+ int getNumIncomingChans() {
+ return mNumIncomingChans;
+ }
+
+ int getOutgoingNumChans() {
+ return mNumOutgoingChans;
+ }
+
+ // call these next two after it is decided what effects we will be using for the duration:
+
+ std::vector<ProcessPlugin*> allocateIncomingEffects(int nIncomingChans) {
+ mNumIncomingChans = nIncomingChans;
+ if (incomingEffectsAllocated) {
+ std::cerr << "*** Effects.h: attempt to allocate incoming effects more than once\n";
+ std::exit(1);
+ }
+ std::vector<ProcessPlugin*> incomingEffects;
+ if (inCompressor) {
+ assert(inCompressorP == nullptr);
+ inCompressorP = new Compressor(mNumIncomingChans, gVerboseFlag, inCompressorPreset);
+ if (gVerboseFlag) { std::cout << "Set up INCOMING COMPRESSOR\n"; }
+ incomingEffects.push_back(inCompressorP);
+ }
+ if (inZitarev) {
+ assert(inZitarevP == nullptr);
+ inZitarevP = new Reverb(mNumIncomingChans,mNumIncomingChans, 1.0 + zitarevInLevel);
+ if (gVerboseFlag) { std::cout << "Set up INCOMING REVERB (Zitarev)\n"; }
+ incomingEffects.push_back(inZitarevP);
+ }
+ if (inFreeverb) {
+ assert(inFreeverbP == nullptr);
+ inFreeverbP = new Reverb(mNumIncomingChans, mNumIncomingChans, freeverbInLevel);
+ if (gVerboseFlag) { std::cout << "Set up INCOMING REVERB (Freeverb)\n"; }
+ incomingEffects.push_back(inFreeverbP);
+ }
+ // LIMITER MUST GO LAST:
+ if ( mLimit == LIMITER_INCOMING || mLimit == LIMITER_BOTH) {
+ if (gVerboseFlag) {
+ std::cout << "Set up INCOMING LIMITER for " << mNumIncomingChans << " input channels\n";
+ }
+ assert(inLimiterP == nullptr);
+ inLimiterP = new Limiter(mNumIncomingChans, 1, gVerboseFlag); // mNumClientsAssumed not needed this direction
+ // Never needed in normal practice for incoming limiter: inLimiterP->setWarningAmplitude(limiterWarningAmplitude);
+ incomingEffects.push_back(inLimiterP);
+ }
+ incomingEffectsAllocated = true;
+ return incomingEffects;
+ }
+
+ std::vector<ProcessPlugin*> allocateOutgoingEffects(int nOutgoingChans) {
+ mNumOutgoingChans = nOutgoingChans;
+ if (outgoingEffectsAllocated) {
+ std::cerr << "*** Effects.h: attempt to allocate outgoing effects more than once\n";
+ std::exit(1);
+ }
+ std::vector<ProcessPlugin*> outgoingEffects;
+ if (outCompressor) {
+ assert(outCompressorP == nullptr);
+ outCompressorP = new Compressor(mNumOutgoingChans, gVerboseFlag, outCompressorPreset);
+ if (gVerboseFlag) { std::cout << "Set up OUTGOING COMPRESSOR\n"; }
+ outgoingEffects.push_back(outCompressorP);
+ }
+ if (outZitarev) {
+ assert(outZitarevP == nullptr);
+ outZitarevP = new Reverb(mNumOutgoingChans, mNumOutgoingChans, 1.0 + zitarevOutLevel);
+ if (gVerboseFlag) { std::cout << "Set up OUTGOING REVERB (Zitarev)\n"; }
+ outgoingEffects.push_back(outZitarevP);
+ }
+ if (outFreeverb) {
+ assert(outFreeverbP == nullptr);
+ outFreeverbP = new Reverb(mNumOutgoingChans, mNumOutgoingChans, freeverbOutLevel);
+ if (gVerboseFlag) { std::cout << "Set up OUTGOING REVERB (Freeverb)\n"; }
+ outgoingEffects.push_back(outFreeverbP);
+ }
+ // LIMITER MUST GO LAST:
+ if ( mLimit != LIMITER_NONE) {
+ if ( mLimit == LIMITER_OUTGOING || mLimit == LIMITER_BOTH) {
+ if (gVerboseFlag) {
+ std::cout << "Set up OUTGOING LIMITER for "
+ << mNumOutgoingChans << " output channels and "
+ << mNumClientsAssumed << " assumed client(s) ...\n";
+ }
+ assert(outLimiterP == nullptr);
+ outLimiterP = new Limiter(mNumOutgoingChans,mNumClientsAssumed);
+ outLimiterP->setWarningAmplitude(limiterWarningAmplitude);
+ // do not have mSampleRate yet, so cannot call limiter->init(mSampleRate) here
+ outgoingEffects.push_back(outLimiterP);
+ }
+ }
+ outgoingEffectsAllocated = true;
+ return outgoingEffects;
+ }
+
+ void printHelp(char* command, char helpCase) {
+ std::cout << "HELP for `" << command << "' (end-of-line comments start with `//')\n";
+ std::cout << "\n";
+ std::cout << "Examples:\n";
+ std::cout << "\n";
+ if (helpCase == 0 || helpCase == 'f') { //
+ std::cout << command << " 0.3 // add a default outgoing compressor (for voice) and incoming reverb (freeverb) with wetness 0.3 (wetness from 0 to 1)\n";
+ std::cout << command << " 1.3 // add a default outgoing compressor (for voice) and incoming reverb (zitarev) with wetness 0.3 = 1.3-1 (i.e., 1+ to 2 is for zitarev)\n";
+ std::cout << "\n";
+ std::cout << command << " \"o:c i:f(0.3)\" // outgoing-compressor and incoming-freeverb example above using more general string argument\n";
+ std::cout << command << " \"o:c i:z(0.3)\" // outgoing-compressor and incoming-zitarev example above using more general string argument\n";
+ std::cout << command << " \"o:c(1)\" // outgoing compressor, using preset 1 (designed for voice - see below for details)\n";
+ std::cout << command << " \"o:c(2)\" // outgoing compressor, using preset 2 (for horns)\n";
+ std::cout << command << " \"o:c(3)\" // outgoing compressor, using preset 3 (for snare)\n";
+ std::cout << command << " \"o:c(c:compressionRatio t:thresholdDB a:attackTimeMS r:releaseTimeMS g:makeUpGainDB)\" // general compression parameter specification (all floats)\n";
+ std::cout << command << " \"o:c(c:2 t:-24 a:15 r:40 g:2)\" // outgoing compressor, preset 1 details\n";
+ std::cout << command << " \"o:c(c:3 t:-10 a:100 r:250 g:2)\" // outgoing compressor, preset 2 details\n";
+ std::cout << command << " \"o:c(c:5 t:-4 a:5 r:150 g:3)\" // outgoing compressor, preset 3 details\n";
+ std::cout << " For these and more suggested compression settings, see http://www.anythingpeaceful.org/sonar/settings/comp.html\n";
+ std::cout << "\n";
+ }
+ if (helpCase == 0 || helpCase == 'O') { // limiter (-O option most likely)
+ std::cout << command << " i // add limiter to INCOMING audio from network (only helpful for floats, i.e., -b32 used by server)\n";
+ std::cout << command << " o // add limiter to OUTGOING audio to network (prevents your sound from harshly clipping going out)\n";
+ std::cout << command << " ow // also warn and advise on levels when outgoing limiter compresses audio near clipping\n";
+ std::cout << command << " io // add limiter to both INCOMING and OUTGOING audio\n";
+ std::cout << command << " iow // limiters both ways and compression warnings on outgoing direction only\n";
+ std::cout << "\n";
+ }
+ if (helpCase == 0 || helpCase == 'a') { // assumedNumClients (-a option)
+ std::cout << command << " 1 // assume 1 client - fine for loopback test, or if only one client plays at a time, or server uses -b32 and -Oi is used\n";
+ std::cout << command << " 2 // assume 2 clients possibly playing at the same time\n";
+ std::cout << command << " N // any integer N>0 can be used - the outgoing limiter will divide final amplitude by 1/sqrt(N) to reduce overages in server\n";
+ std::cout << "\n";
+ }
+ }
+
+ // ----------- Compressor stuff --------------
+
+ int setCompressorPresetIndexFrom1(unsigned long presetIndexFrom1, InOrOut io) {
+ int returnCode = 0;
+ if (presetIndexFrom1 <= 0 || presetIndexFrom1 > CompressorPresets::numPresets) {
+ std::cerr << "*** Effects.h: setCompressorPresetFrom1: Index " << presetIndexFrom1 << " out of range\n";
+ returnCode = 1;
+ } else {
+ CompressorPreset stdPreset = CompressorPresets::standardPresets[presetIndexFrom1-1];
+ if (io == IO_IN) {
+ inCompressorPreset = stdPreset;
+ } else if (io == IO_OUT) {
+ outCompressorPreset = stdPreset;
+ } else if (io != IO_NEITHER) {
+ std::cerr << "*** Effects.h: setCompressorPresetFrom1: Invalid InOrOut value " << io << "\n";
+ returnCode = 1;
+ }
+ }
+ return returnCode;
+ }
+
+ int parseCompresserArgs(char* args, InOrOut inOrOut) {
+ // args can be integerPresetNumberFrom1 or (all optional, any order):
+ // c:compressionRatio, a:attackTimeMS, r:releaseTimeMS, g:makeUpGain
+ int returnCode = 0;
+ if (not isalpha(args[0])) {
+ int presetIndexFrom1 = atoi(args);
+ setCompressorPresetIndexFrom1(presetIndexFrom1,inOrOut);
+ } else {
+ // args can be presetIndexFrom1, handled above, or (all optional, any order):
+ // c(c:compressionRatio, t:thresholdDB, a:attackTimeMS, r:releaseTimeMS, g:makeUpGainDB)
+ // See ./CompressorPresets.h for example settings.
+ if (gVerboseFlag) {
+ std::cout << "parseCompressorArgs = " << args << std::endl;
+ }
+ ulong argLen = strlen(args);
+ char lastParam = '\0';
+
+ CompressorPreset newPreset(CompressorPresets::voice); // Anything unset gets voice value (most gentle)
+
+ int nSkip = 0;
+ for (ulong i=0; i<argLen; i++) {
+ if (nSkip > 0) {
+ nSkip--;
+ continue;
+ }
+ char ch = args[i];
+ switch(ch) {
+ case ' ': break;
+ case '\t': break;
+ case 'c': case 't': case 'a': case 'r': case 'g':
+ lastParam = ch;
+ break;
+ case ':': break;
+ default: // must be a floating-point number at this point:
+ if (ch!='-' && isalpha(ch)) {
+ std::cerr << "*** Effects.h: parseCompressorArgs: " << ch << " not recognized in args = " << args << "\n";
+ returnCode = 2;
+ } else { // must have a digit or '-' or '.'
+ assert(ch=='-'||ch=='.'||isdigit(ch));
+ float paramValue = -1.0e10;
+ for (ulong j=i; j<argLen; j++) { // scan ahead for end of number
+ if (args[j] == ',' || args[j] == ' ' || j==argLen-1) { // comma or space required between parameters
+ char argsj = args[j];
+ if (j<argLen-1) { // there's more
+ args[j] = '\0';
+ }
+ paramValue = atof(&args[i]);
+ args[j] = argsj;
+ nSkip = j-i;
+ break;
+ }
+ }
+ if (paramValue == -1.0e10) {
+ std::cerr << "*** Effects.h: parseCompressorArgs: Could not find parameter for "
+ << lastParam << " in args = " << args << "\n";
+ returnCode = 2;
+ } else {
+ switch (lastParam) {
+ case 'c':
+ newPreset.ratio = paramValue;
+ break;
+ case 't':
+ newPreset.thresholdDB = paramValue;
+ break;
+ case 'a':
+ newPreset.attackMS = paramValue;
+ break;
+ case 'r':
+ newPreset.releaseMS = paramValue;
+ break;
+ case 'g':
+ newPreset.makeUpGainDB = paramValue;
+ break;
+ default: // cannot happen:
+ std::cerr << "*** Effects.h: parseCompressorArgs: lastParam " << lastParam << " invalid\n";
+ returnCode = 3; // "reality failure"
+ } // switch(lastParam)
+ } // have valid parameter from atof
+ } // have valid non-alpha char for parameter
+ } // switch(ch)
+ } // for (ulong i=0; i<argLen; i++) {
+ if (inOrOut == IO_IN) {
+ inCompressorPreset = newPreset;
+ } else if (inOrOut == IO_OUT) {
+ outCompressorPreset = newPreset;
+ } else if (inOrOut != IO_NEITHER) {
+ std::cerr << "*** Effects.h: parseCompressorArgs: invalid InOrOut value " << inOrOut << "\n";
+ returnCode = 2;
+ }
+ } // long-form compressor args
+ return returnCode;
+ } // int parseCompresserArgs(char* args, InOrOut inOrOut)
+
+ // ============== General argument processing for all effects =================
+
+ int parseEffectsOptArg(char* cmd, char* optarg) {
+ int returnCode = 0; // 0 means go, 1 means exit without error, higher => error exit
+
+ char c = optarg[0];
+ if (c == '-' || c==0) {
+ // happens when no -f argument specified
+ returnCode = 2;
+ } else if (not isalpha(c)) { // backward compatibility why not?, e.g., "-f 0.5"
+ // -f reverbLevelFloat
+ mReverbLevel = atof(optarg);
+ outCompressor = true;
+ inZitarev = mReverbLevel > 1.0;
+ inFreeverb = mReverbLevel <= 1.0;
+ if (inZitarev) {
+ zitarevInLevel = mReverbLevel - 1.0; // wetness from 0 to 1
+ }
+ if (inFreeverb) {
+ freeverbInLevel = mReverbLevel; // wetness from 0 to 1
+ }
+ } else { // long-form argument:
+ // -f "i:[c][f|z][(reverbLevel)]], o:[c][f|z][(rl)]"
+ // c can be c(integerPresetNumberFrom1) or (all optional, any order):
+ // c(c:compressionRatio, a:attackTimeMS, r:releaseTimeMS, g:makeUpGain)
+ if (gVerboseFlag) {
+ std::cout << cmd << " argument = " << optarg << std::endl;
+ }
+ ulong argLen = strlen(optarg);
+
+ for (ulong i=0; i<argLen; i++) {
+ if (optarg[i]!=')' && parenLevel>0) { continue; }
+ switch(optarg[i]) {
+ case ' ': break;
+ case ',': break;
+ case ';': break;
+ case '\t': break;
+ case 'h': printHelp(cmd,'f'); returnCode = 1; break;
+ case 'i': io=IO_IN; break;
+ case 'o': io=IO_OUT; break;
+ case ':': break;
+ case 'c': if (io==IO_IN) { inCompressor = true; } else if (io==IO_OUT) { outCompressor = true; }
+ else { std::cerr << "-f arg `" << optarg << "' malformed\n"; exit(1); }
+ lastEffect = 'c';
+ break;
+ case 'f': if (io==IO_IN) { inFreeverb = true; } else if (io==IO_OUT) { outFreeverb = true; }
+ else { std::cerr << "-f arg `" << optarg << "' malformed\n"; exit(1); }
+ lastEffect = 'f';
+ break;
+ case 'z': if (io==IO_IN) { inZitarev = true; } else if (io==IO_OUT) { outZitarev = true; }
+ else { std::cerr << "-f arg `" << optarg << "' malformed\n"; exit(1); }
+ lastEffect = 'z';
+ break;
+ case '(': parenLevel++;
+ for (ulong j=i+1; j<argLen; j++) {
+ if (optarg[j] == ')') {
+ optarg[j] = '\0';
+ switch(lastEffect) {
+ case 'c': {
+ returnCode += parseCompresserArgs(&optarg[i+1],io);
+ break; }
+ case 'z': {
+ float farg = atof(&optarg[i+1]);
+ if (io==IO_IN) {
+ zitarevInLevel = farg;
+ } else if (io==IO_OUT) {
+ zitarevOutLevel = farg;
+ } // else ignore the argument
+ break; }
+ case 'f': {
+ float farg = atof(&optarg[i+1]);
+ if (io==IO_IN) {
+ freeverbInLevel = farg;
+ } else if (io==IO_OUT) {
+ freeverbOutLevel = farg;
+ } // else ignore the argument
+ break; }
+ default: { // ignore
+ break; }
+ }
+ optarg[j] = ')';
+ break;
+ }
+ }
+ break;
+ case ')': parenLevel--;
+ break;
+ default:
+ break; // ignore
+ } // switch(optarg[i])
+ }
+ }
+ return returnCode;
+ }
+
+ int parseLimiterOptArg(char* cmd, char* optarg) {
+ int returnCode = 0;
+ lastEffect = 'O'; // OverflowLimiter
+ char ch = tolower(optarg[0]);
+ if (ch == '-' || ch == 0) {
+ std::cerr << cmd << " argument i, o, or io is REQUIRED\n";
+ returnCode = 2;
+ } else if (ch == 'h') {
+ printHelp(cmd,'O');
+ returnCode = 1;
+ } else {
+ bool haveIncoming = false;
+ bool haveOutgoing = false;
+ bool haveWarnings = false;
+ for (int i=0; i<strlen(optarg); i++) {
+ ch = tolower(optarg[i]);
+ switch(ch) {
+ case ' ': break;
+ case '\t': break;
+ case 'i':
+ haveIncoming = true;
+ break;
+ case 'o':
+ haveOutgoing = true;
+ break;
+ case 'w':
+ haveWarnings = true;
+ break;
+ case 'n':
+ haveIncoming = false;
+ haveOutgoing = false;
+ break;
+ default:
+ std::cerr << "*** Effects.h: parseLimiterOptArg: Unrecognized option " << ch << "\n";
+ returnCode = 2;
+ } // switch(ch)
+ } // process optarg char ch
+ mLimit = (haveIncoming && haveOutgoing ? LIMITER_BOTH
+ : (haveIncoming ? LIMITER_INCOMING
+ : (haveOutgoing ? LIMITER_OUTGOING : LIMITER_NONE)));
+ if (haveWarnings) {
+ limiterWarningAmplitude = 0.5; // KEEP IN SYNC WITH LIMITER THRESHOLD/CEILING 'softClipLevel' in ../faust-src/limiterdsp.dsp
+ // the warning amplitude and limiter compression threshold can of course be brought as a parameters, e.g. w(0.5)
+ }
+ if (gVerboseFlag) {
+ if(haveIncoming) {
+ std::cout << "Set up INCOMING Overflow Limiter\n";
+ }
+ if(haveOutgoing) {
+ std::cout << "Set up OUTGOING Overflow Limiter\n";
+ }
+ if(haveWarnings) {
+ std::cout << "Enable DISTORTION WARNINGS in Overflow Limiters\n";
+ }
+ if(not haveIncoming and not haveOutgoing) {
+ std::cout << "Set up NO Overflow Limiters\n";
+ }
+ } // gVerboseFlag
+ } // optarg cases
+ return returnCode;
+ } // parseLimiterOptArg()
+
+ int parseAssumedNumClientsOptArg(char* cmd, char* optarg) {
+ int returnCode = 0;
+ lastEffect = 'a'; // assumedNumClients
+ char ch = optarg[0];
+ if (ch == 'h') {
+ printHelp(cmd,'a');
+ returnCode = 1;
+ } else if (ch == '-' || isalpha(ch) || ch == 0) {
+ std::cerr << cmd << " argument help or integer > 0 is REQUIRED\n";
+ returnCode = 2;
+ } else {
+ mNumClientsAssumed = atoi(optarg);
+ if(mNumClientsAssumed < 1) {
+ std::cerr << "-p ERROR: Must have at least one assumed sound source: "
+ << atoi(optarg) << " is not supported." << std::endl;
+ returnCode = 2;
+ }
+ }
+ return returnCode;
+ }
+
+};
diff --git a/src/JMess.cpp b/src/JMess.cpp
index 8cdab74..f348617 100644
--- a/src/JMess.cpp
+++ b/src/JMess.cpp
@@ -78,7 +78,7 @@ JMess::~JMess()
*
*/
//-------------------------------------------------------------------------------
-void JMess::writeOutput(QString xmlOutFile)
+void JMess::writeOutput(__attribute__((unused)) QString xmlOutFile)
{
// QDomDocument jmess_xml; QDomElement root;
// QDomElement connection; QDomElement output;
@@ -171,13 +171,12 @@ void JMess::setConnectedPorts()
void JMess::connectSpawnedPorts(int nChans, int hubPatch)
// called from UdpHubListener::connectMesh
{
-
QMutexLocker locker(&sJMessMutex);
-
+
QString IPS[gMAX_WAIRS];
int ctr = 0;
- const char **ports, **connections; //vector of ports and connections
+ const char **ports; //, **connections; //vector of ports and connections
QVector<QString> OutputInput(2); //helper variable
//Get active output ports.
@@ -202,7 +201,7 @@ void JMess::connectSpawnedPorts(int nChans, int hubPatch)
// qDebug() << ports[out_i] << systemPort << s;
}
}
-// for (int i = 0; i<ctr; i++) qDebug() << IPS[i];
+ //for (int i = 0; i<ctr; i++) qDebug() << IPS[i];
disconnectAll();
int k = 0;
@@ -217,8 +216,8 @@ void JMess::connectSpawnedPorts(int nChans, int hubPatch)
if ((hubPatch == JackTrip::CLIENTECHO)||(hubPatch == JackTrip::FULLMIX)) k = i;
else if (hubPatch == JackTrip::CLIENTFOFI) k = (j+(i+1))%ctr;
for (int l = 1; l<=nChans; l++) { // chans are 1-based
-// qDebug() << "connect " << IPS[i]+":receive_"+QString::number(l)
-// <<"with " << IPS[k]+":send_"+QString::number(l);
+ //qDebug() << "connect " << IPS[i]+":receive_"+QString::number(l)
+ //<<"with " << IPS[k]+":send_"+QString::number(l);
QString left = IPS[i] +
":receive_" + QString::number(l);
@@ -244,8 +243,8 @@ void JMess::connectSpawnedPorts(int nChans, int hubPatch)
for (int j = 0; j<jLimit; j++) {
k = (j+(i+1))%ctr;
for (int l = 1; l<=nChans; l++) { // chans are 1-based
-// qDebug() << "connect " << IPS[i]+":receive_"+QString::number(l)
-// <<"with " << IPS[k]+":send_"+QString::number(l);
+ //qDebug() << "connect " << IPS[i]+":receive_"+QString::number(l)
+ //<<"with " << IPS[k]+":send_"+QString::number(l);
QString left = IPS[i] +
":receive_" + QString::number(l);
@@ -371,7 +370,7 @@ void JMess::disconnectAll()
it != mConnectedPorts.end(); ++it) {
OutputInput = *it;
- if (jack_disconnect(mClient, OutputInput[0].toLatin1(), OutputInput[1].toLatin1())) {
+ if (jack_disconnect(mClient, OutputInput[0].toUtf8(), OutputInput[1].toUtf8())) {
cerr << "WARNING: port: " << qPrintable(OutputInput[0])
<< "and port: " << qPrintable(OutputInput[1])
<< " could not be disconnected.\n";
@@ -388,7 +387,7 @@ void JMess::disconnectAll()
* read the file.
*/
//-------------------------------------------------------------------------------
-int JMess::parseXML(QString xmlInFile)
+int JMess::parseXML(__attribute__((unused)) QString xmlInFile)
{
// mPortsToConnect.clear();
// QString errorStr;
@@ -455,7 +454,7 @@ int JMess::parseXML(QString xmlInFile)
*
*/
//-------------------------------------------------------------------------------
-void JMess::connectPorts(QString xmlInFile)
+void JMess::connectPorts(__attribute__((unused)) QString xmlInFile)
{
QVector<QString> OutputInput(2);
diff --git a/src/JackAudioInterface.cpp b/src/JackAudioInterface.cpp
index 70c7632..06ff4c8 100644
--- a/src/JackAudioInterface.cpp
+++ b/src/JackAudioInterface.cpp
@@ -66,7 +66,7 @@ JackAudioInterface::JackAudioInterface(JackTrip* jacktrip,
int NumNetRevChans,
#endif // endwhere
AudioInterface::audioBitResolutionT AudioBitResolution,
- const char* ClientName) :
+ QString ClientName) :
AudioInterface(jacktrip,
NumInChans, NumOutChans,
#ifdef WAIR // wair
@@ -81,6 +81,7 @@ JackAudioInterface::JackAudioInterface(JackTrip* jacktrip,
mBitResolutionMode(AudioBitResolution),
mClient(NULL),
mClientName(ClientName),
+ mBroadcast(false),
mJackTrip(jacktrip)
{}
@@ -171,6 +172,7 @@ void JackAudioInterface::setupClient()
// Initialize Buffer array to read and write audio
mInBuffer.resize(mNumInChans);
mOutBuffer.resize(mNumOutChans);
+ mBroadcastBuffer.resize(mNumOutChans);
}
@@ -198,6 +200,18 @@ void JackAudioInterface::createChannels()
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsOutput, 0);
}
+ //Create Broadcast Ports
+ if (mBroadcast) {
+ mBroadcastPorts.resize(mNumOutChans);
+ for (int i = 0; i < mNumInChans; i++)
+ {
+ QString outName;
+ QTextStream (&outName) << "broadcast_" << i+1;
+ mBroadcastPorts[i] = jack_port_register (mClient, outName.toLatin1(),
+ JACK_DEFAULT_AUDIO_TYPE,
+ JackPortIsOutput, 0);
+ }
+ }
}
@@ -273,7 +287,9 @@ int JackAudioInterface::stopProcess() const
void JackAudioInterface::jackShutdown (void*)
{
//std::cout << "The Jack Server was shut down!" << std::endl;
- throw std::runtime_error("The Jack Server was shut down!");
+ JackTrip::sJackStopped = true;
+ std::cout << "The Jack Server was shut down!" << std::endl;
+ //throw std::runtime_error("The Jack Server was shut down!");
//std::cout << "Exiting program..." << std::endl;
//std::exit(1);
}
@@ -283,10 +299,15 @@ void JackAudioInterface::jackShutdown (void*)
//*******************************************************************************
int JackAudioInterface::processCallback(jack_nframes_t nframes)
{
+ if(mProcessingAudio) {
+ std::cerr << "*** JackAudioInterface.cpp: DROPPED A BUFFER because AudioInterface::callback() not finished\n";
+ return 1;
+ }
+
// Get input and output buffers from JACK
//-------------------------------------------------------------------
for (int i = 0; i < mNumInChans; i++) {
- // Input Ports are READ ONLY
+ // Input Ports are READ ONLY and change as needed (no locks) - make a copy for debugging
mInBuffer[i] = (sample_t*) jack_port_get_buffer(mInPorts[i], nframes);
}
for (int i = 0; i < mNumOutChans; i++) {
@@ -302,6 +323,14 @@ int JackAudioInterface::processCallback(jack_nframes_t nframes)
//-------------------------------------------------------------------
AudioInterface::callback(mInBuffer, mOutBuffer, nframes);
+
+ if (mBroadcast) {
+ for (int i = 0; i < mNumOutChans; i++) {
+ // Broadcast Ports are WRITABLE
+ mBroadcastBuffer[i] = (sample_t*) jack_port_get_buffer(mBroadcastPorts[i], nframes);
+ }
+ AudioInterface::broadcastCallback(mBroadcastBuffer, nframes);
+ }
return 0;
}
@@ -377,7 +406,7 @@ void JackAudioInterface::connectDefaultPorts()
-// OLD CODE
+// OLD CODE (some moved to parent class AudioInterface.cpp)
// ==============================================================================
//*******************************************************************************
diff --git a/src/JackAudioInterface.h b/src/JackAudioInterface.h
index 7886d82..5a1b4b0 100644
--- a/src/JackAudioInterface.h
+++ b/src/JackAudioInterface.h
@@ -78,7 +78,7 @@ public:
int NumNetRevChans,
#endif // endwhere
AudioInterface::audioBitResolutionT AudioBitResolution = AudioInterface::BIT16,
- const char* ClientName = "JackTrip");
+ QString ClientName = "JackTrip");
/// \brief The class destructor
virtual ~JackAudioInterface();
@@ -104,6 +104,7 @@ public:
{ std::cout << "WARNING: Setting the Sample Rate in Jack mode has no effect." << std::endl; }
virtual void setBufferSizeInSamples(uint32_t /*buf_size*/)
{ std::cout << "WARNING: Setting the Sample Rate in Jack mode has no effect." << std::endl; }
+ virtual void enableBroadcastOutput() {mBroadcast = true;}
//------------------------------------------------------------------
//--------------GETTERS---------------------------------------------
@@ -113,7 +114,7 @@ public:
virtual uint32_t getBufferSizeInSamples() const;
/// \brief Get the Jack Server Buffer Size, in bytes
virtual uint32_t getBufferSizeInBytes() const
- { return (getBufferSizeInSamples() * getAudioBitResolution()/8); }
+ { return (getBufferSizeInSamples() * getAudioBitResolution() / 8); }
/// \brief Get size of each audio per channel, in bytes
virtual size_t getSizeInBytesPerChannel() const;
//------------------------------------------------------------------
@@ -177,8 +178,11 @@ private:
QString mClientName; ///< Jack Client Name
QVarLengthArray<jack_port_t*> mInPorts; ///< Vector of Input Ports (Channels)
QVarLengthArray<jack_port_t*> mOutPorts; ///< Vector of Output Ports (Channels)
+ QVarLengthArray<jack_port_t*> mBroadcastPorts; ///< Vector of Output Ports (Channels)
QVarLengthArray<sample_t*> mInBuffer; ///< Vector of Input buffers/channel read from JACK
QVarLengthArray<sample_t*> mOutBuffer; ///< Vector of Output buffer/channel to write to JACK
+ QVarLengthArray<sample_t*> mBroadcastBuffer; ///< Vector of Output buffer/channel to write to JACK
+ bool mBroadcast;
size_t mSizeInBytesPerChannel; ///< Size in bytes per audio channel
QVector<ProcessPlugin*> mProcessPlugins; ///< Vector of ProcesPlugin<EM>s</EM>
JackTrip* mJackTrip; ///< JackTrip mediator class
diff --git a/src/JackTrip.cpp b/src/JackTrip.cpp
index 4ba94af..f672984 100644
--- a/src/JackTrip.cpp
+++ b/src/JackTrip.cpp
@@ -38,6 +38,7 @@
#include "JackTrip.h"
#include "UdpDataProtocol.h"
#include "RingBufferWavetable.h"
+#include "JitterBuffer.h"
#include "jacktrip_globals.h"
#include "JackAudioInterface.h"
#ifdef __RT_AUDIO__
@@ -51,7 +52,6 @@
#include <QHostAddress>
#include <QHostInfo>
#include <QThread>
-#include <QTcpSocket>
#include <QTimer>
#include <QDateTime>
@@ -59,12 +59,15 @@ using std::cout; using std::endl;
//the following function has to remain outside the Jacktrip class definition
//its purpose is to close the app when control c is hit by the user in rtaudio/asio4all mode
-#if defined __WIN_32__
+/*if defined __WIN_32__
void sigint_handler(int sig)
{
exit(0);
}
-#endif
+#endif*/
+
+bool JackTrip::sSigInt = false;
+bool JackTrip::sJackStopped = false;
//*******************************************************************************
JackTrip::JackTrip(jacktripModeT JacktripMode,
@@ -89,15 +92,19 @@ JackTrip::JackTrip(jacktripModeT JacktripMode,
mNumNetRevChans(NumNetRevChans),
#endif // endwhere
mBufferQueueLength(BufferQueueLength),
+ mBufferStrategy(1),
+ mBroadcastQueueLength(0),
mSampleRate(gDefaultSampleRate),
mDeviceID(gDefaultDeviceID),
mAudioBufferSize(gDefaultBufferSizeInSamples),
mAudioBitResolution(AudioBitResolution),
+ mLoopBack(false),
mDataProtocolSender(NULL),
mDataProtocolReceiver(NULL),
mAudioInterface(NULL),
mPacketHeader(NULL),
mUnderRunMode(UnderRunMode),
+ mStopOnTimeout(false),
mSendRingBuffer(NULL),
mReceiveRingBuffer(NULL),
mReceiverBindPort(receiver_bind_port),
@@ -108,20 +115,34 @@ JackTrip::JackTrip(jacktripModeT JacktripMode,
mRedundancy(redundancy),
mJackClientName(gJackDefaultClientName),
mConnectionMode(JackTrip::NORMAL),
+ mTimeoutTimer(this),
+ mSleepTime(100),
+ mElapsedTime(0),
+ mEndTime(0),
+ mTcpClient(this),
+ mUdpSockTemp(this),
mReceivedConnection(false),
mTcpConnectionError(false),
mStopped(false),
+ mHasShutdown(false),
mConnectDefaultAudioPorts(true),
- mIOStatLogStream(std::cout.rdbuf())
+ mIOStatTimeout(0),
+ mIOStatLogStream(std::cout.rdbuf()),
+ mSimulatedLossRate(0.0),
+ mSimulatedJitterRate(0.0),
+ mSimulatedDelayRel(0.0),
+ mUseRtUdpPriority(false),
+ mAudioTesterP(nullptr)
{
createHeader(mPacketHeaderType);
+ sJackStopped = false;
}
//*******************************************************************************
JackTrip::~JackTrip()
{
- wait();
+ //wait();
delete mDataProtocolSender;
delete mDataProtocolReceiver;
delete mAudioInterface;
@@ -134,14 +155,14 @@ JackTrip::~JackTrip()
//*******************************************************************************
void JackTrip::setupAudio(
#ifdef WAIRTOHUB // WAIR
- int ID
+ __attribute__((unused)) int ID
#endif // endwhere
)
{
// Check if mAudioInterface has already been created or not
if (mAudioInterface != NULL) { // if it has been created, disconnet it from JACK and delete it
cout << "WARINING: JackAudio interface was setup already:" << endl;
- cout << "It will be errased and setup again." << endl;
+ cout << "It will be erased and setup again." << endl;
cout << gPrintSeparator << endl;
closeAudio();
}
@@ -157,23 +178,19 @@ void JackTrip::setupAudio(
mAudioBitResolution);
#ifdef WAIRTOHUB // WAIR
-// qDebug() << "mPeerAddress" << mPeerAddress << mPeerAddress.contains(gDOMAIN_TRIPLE);
QString VARIABLE_AUDIO_NAME = WAIR_AUDIO_NAME; // legacy for WAIR
- QByteArray tmp = QString(mPeerAddress).replace(":", ".").toLatin1();
//Set our Jack client name if we're a hub server or a custom name hasn't been set
if (!mPeerAddress.isEmpty() && (mJackClientName.constData() == gJackDefaultClientName.constData())) {
mJackClientName = QString(mPeerAddress).replace(":", "_");
}
-// if ( mPeerAddress.toStdString() != "" &&
-// (mJackClientName == gJackDefaultClientName || mJackTripMode == SERVERPINGSERVER)) {
-// mJackClientName = QString(mPeerAddress).replace(":", ".").toLatin1().constData();
-// }
+ //std::cout << "WAIR ID " << ID << " jacktrip client name set to=" <<
+ // mJackClientName.toStdString() << std::endl;
-// std::cout << "WAIR ID " << ID << " jacktrip client name set to=" <<
-// mJackClientName << std::endl;
#endif // endwhere
-
mAudioInterface->setClientName(mJackClientName);
+ if (0 < mBroadcastQueueLength) {
+ mAudioInterface->enableBroadcastOutput();
+ }
if (gVerboseFlag) std::cout << " JackTrip:setupAudio before mAudioInterface->setup" << std::endl;
mAudioInterface->setup();
@@ -205,17 +222,27 @@ void JackTrip::setupAudio(
#endif
}
+ mAudioInterface->setLoopBack(mLoopBack);
+ if (mAudioTesterP) { // if we're a hub server, this will be a nullptr - MAJOR REFACTOR NEEDED, in my opinion
+ mAudioTesterP->setSampleRate(mSampleRate);
+ }
+ mAudioInterface->setAudioTesterP(mAudioTesterP);
+
std::cout << "The Sampling Rate is: " << mSampleRate << std::endl;
std::cout << gPrintSeparator << std::endl;
int AudioBufferSizeInBytes = mAudioBufferSize*sizeof(sample_t);
std::cout << "The Audio Buffer Size is: " << mAudioBufferSize << " samples" << std::endl;
std::cout << " or: " << AudioBufferSizeInBytes
<< " bytes" << std::endl;
+ if (0 < mBroadcastQueueLength) {
+ std::cout << gPrintSeparator << std::endl;
+ cout << "Broadcast Output is enabled, delay = "
+ << mBroadcastQueueLength * mAudioBufferSize * 1000 / mSampleRate << " ms"
+ << " (" << mBroadcastQueueLength * mAudioBufferSize << " samples)" << endl;
+ }
std::cout << gPrintSeparator << std::endl;
cout << "The Number of Channels is: " << mAudioInterface->getNumInputChannels() << endl;
std::cout << gPrintSeparator << std::endl;
- cout << "The RTAudio device ID is: " << mAudioInterface->getDeviceID() << endl;
- std::cout << gPrintSeparator << std::endl;
QThread::usleep(100);
}
@@ -235,11 +262,11 @@ void JackTrip::closeAudio()
//*******************************************************************************
void JackTrip::setupDataProtocol()
{
+ double simulated_max_delay = mSimulatedDelayRel * getBufferSizeInSamples() / getSampleRate();
// Create DataProtocol Objects
switch (mDataProtocol) {
case UDP:
std::cout << "Using UDP Protocol" << std::endl;
- std::cout << gPrintSeparator << std::endl;
QThread::usleep(100);
mDataProtocolSender = new UdpDataProtocol(this, DataProtocol::SENDER,
//mSenderPeerPort, mSenderBindPort,
@@ -248,6 +275,15 @@ void JackTrip::setupDataProtocol()
mDataProtocolReceiver = new UdpDataProtocol(this, DataProtocol::RECEIVER,
mReceiverBindPort, mReceiverPeerPort,
mRedundancy);
+ if (0.0 < mSimulatedLossRate || 0.0 < mSimulatedJitterRate || 0.0 < simulated_max_delay) {
+ mDataProtocolReceiver->setIssueSimulation(mSimulatedLossRate, mSimulatedJitterRate, simulated_max_delay);
+ }
+ mDataProtocolSender->setUseRtPriority(mUseRtUdpPriority);
+ mDataProtocolReceiver->setUseRtPriority(mUseRtUdpPriority);
+ if (mUseRtUdpPriority) {
+ cout << "Using RT thread priority for UDP data" << endl;
+ }
+ std::cout << gPrintSeparator << std::endl;
break;
case TCP:
throw std::invalid_argument("TCP Protocol is not implemented");
@@ -277,6 +313,12 @@ void JackTrip::setupRingBuffers()
/// \todo Make all this operations cleaner
//int total_audio_packet_size = getTotalAudioPacketSizeInBytes();
int slot_size = getRingBuffersSlotSize();
+ if (0 <= mBufferStrategy) {
+ mUnderRunMode = ZEROS;
+ }
+ else if (0 > mBufferQueueLength) {
+ throw std::invalid_argument("Auto queue is not supported by RingBuffer");
+ }
switch (mUnderRunMode) {
case WAVETABLE:
@@ -290,13 +332,23 @@ void JackTrip::setupRingBuffers()
mReceiveRingBuffer = new RingBufferWavetable(mAudioInterface->getSizeInBytesPerChannel() * mNumChans,
mBufferQueueLength);
*/
-
break;
case ZEROS:
mSendRingBuffer = new RingBuffer(slot_size,
gDefaultOutputQueueLength);
- mReceiveRingBuffer = new RingBuffer(slot_size,
- mBufferQueueLength);
+ if (0 > mBufferStrategy) {
+ mReceiveRingBuffer = new RingBuffer(slot_size,
+ mBufferQueueLength);
+ }
+ else {
+ cout << "Using JitterBuffer strategy " << mBufferStrategy << endl;
+ if (0 > mBufferQueueLength) {
+ cout << "Using AutoQueue 1/" << -mBufferQueueLength << endl;
+ }
+ mReceiveRingBuffer = new JitterBuffer(mAudioBufferSize, mBufferQueueLength,
+ mSampleRate, mBufferStrategy,
+ mBroadcastQueueLength, mNumChans, mAudioBitResolution);
+ }
/*
mSendRingBuffer = new RingBuffer(mAudioInterface->getSizeInBytesPerChannel() * mNumChans,
gDefaultOutputQueueLength);
@@ -312,17 +364,28 @@ void JackTrip::setupRingBuffers()
//*******************************************************************************
-void JackTrip::setPeerAddress(const char* PeerHostOrIP)
+void JackTrip::setPeerAddress(QString PeerHostOrIP)
{
mPeerAddress = PeerHostOrIP;
}
//*******************************************************************************
-void JackTrip::appendProcessPlugin(ProcessPlugin* plugin)
+void JackTrip::appendProcessPluginToNetwork(ProcessPlugin* plugin)
{
- mProcessPlugins.append(plugin);
- //mAudioInterface->appendProcessPlugin(plugin);
+ if (plugin) {
+ mProcessPluginsToNetwork.append(plugin); // ownership transferred
+ //mAudioInterface->appendProcessPluginToNetwork(plugin);
+ }
+}
+
+//*******************************************************************************
+void JackTrip::appendProcessPluginFromNetwork(ProcessPlugin* plugin)
+{
+ if (plugin) {
+ mProcessPluginsFromNetwork.append(plugin); // ownership transferred
+ //mAudioInterface->appendProcessPluginFromNetwork(plugin);
+ }
}
@@ -333,20 +396,20 @@ void JackTrip::startProcess(
#endif // endwhere
)
{ //signal that catches ctrl c in rtaudio-asio mode
-#if defined (__WIN_32__)
+/*#if defined (__WIN_32__)
if (signal(SIGINT, sigint_handler) == SIG_ERR) {
perror("signal");
exit(1);
}
-#endif
+#endif*/
// Check if ports are already binded by another process on this machine
// ------------------------------------------------------------------
if (gVerboseFlag) std::cout << "step 1" << std::endl;
if (gVerboseFlag) std::cout << " JackTrip:startProcess before checkIfPortIsBinded(mReceiverBindPort)" << std::endl;
#if defined __WIN_32__
- //cc fixed windows crash with this print statement! hope to delete
-// qDebug() << "before mJackTrip->startProcess" << mReceiverBindPort<< mSenderBindPort;
+ //cc fixed windows crash with this print statement!
+ //qDebug() << "before mJackTrip->startProcess" << mReceiverBindPort<< mSenderBindPort;
#endif
checkIfPortIsBinded(mReceiverBindPort);
if (gVerboseFlag) std::cout << " JackTrip:startProcess before checkIfPortIsBinded(mSenderBindPort)" << std::endl;
@@ -365,18 +428,24 @@ void JackTrip::startProcess(
setupRingBuffers();
// Connect Signals and Slots
// -------------------------
- QObject::connect(mPacketHeader, SIGNAL(signalError(const char*)),
- this, SLOT(slotStopProcesses()), Qt::QueuedConnection);
+ QObject::connect(mPacketHeader, &PacketHeader::signalError,
+ this, &JackTrip::slotStopProcessesDueToError, Qt::QueuedConnection);
QObject::connect(mDataProtocolReceiver, SIGNAL(signalReceivedConnectionFromPeer()),
this, SLOT(slotReceivedConnectionFromPeer()),
Qt::QueuedConnection);
- QObject::connect(this, SIGNAL(signalUdpTimeOut()),
- this, SLOT(slotStopProcesses()), Qt::QueuedConnection);
+ //QObject::connect(this, SIGNAL(signalUdpTimeOut()),
+ // this, SLOT(slotStopProcesses()), Qt::QueuedConnection);
+ QObject::connect((UdpDataProtocol *)mDataProtocolReceiver, &UdpDataProtocol::signalUdpWaitingTooLong, this,
+ &JackTrip::slotUdpWaitingTooLong, Qt::QueuedConnection);
+ QObject::connect(mDataProtocolSender, &DataProtocol::signalCeaseTransmission,
+ this, &JackTrip::slotStopProcessesDueToError, Qt::QueuedConnection);
+ QObject::connect(mDataProtocolReceiver, &DataProtocol::signalCeaseTransmission,
+ this, &JackTrip::slotStopProcessesDueToError, Qt::QueuedConnection);
//QObject::connect(mDataProtocolSender, SIGNAL(signalError(const char*)),
// this, SLOT(slotStopProcesses()), Qt::QueuedConnection);
- //QObject::connect(mDataProtocolReceiver, SIGNAL(signalError(const char*)),
- // this, SLOT(slotStopProcesses()), Qt::QueuedConnection);
+ QObject::connect(mDataProtocolReceiver, SIGNAL(signalError(const char*)),
+ this, SLOT(slotStopProcesses()), Qt::QueuedConnection);
// Start the threads for the specific mode
// ---------------------------------------
@@ -396,8 +465,7 @@ void JackTrip::startProcess(
if (gVerboseFlag) std::cout << "step 2C client only" << std::endl;
if (gVerboseFlag) std::cout << " JackTrip:startProcess case CLIENTTOPINGSERVER before clientPingToServerStart" << std::endl;
if ( clientPingToServerStart() == -1 ) { // if error on server start (-1) we return inmediatly
- mTcpConnectionError = true;
- slotStopProcesses();
+ stop("Peer Address has to be set if you run in CLIENTTOPINGSERVER mode");
return;
}
break;
@@ -405,15 +473,18 @@ void JackTrip::startProcess(
if (gVerboseFlag) std::cout << "step 2S server only (same as 2s)" << std::endl;
if (gVerboseFlag) std::cout << " JackTrip:startProcess case SERVERPINGSERVER before serverStart" << std::endl;
if ( serverStart(true) == -1 ) { // if error on server start (-1) we return inmediatly
- slotStopProcesses();
+ stop();
return;
}
break;
default:
- throw std::invalid_argument("Jacktrip Mode undefined");
+ throw std::invalid_argument("Jacktrip Mode undefined");
break;
}
+}
+void JackTrip::completeConnection()
+{
// Have the threads share a single socket that operates at full duplex.
#if defined (__WIN_32__)
SOCKET sock_fd = INVALID_SOCKET;
@@ -439,21 +510,27 @@ void JackTrip::startProcess(
QThread::msleep(1);
if (gVerboseFlag) std::cout << "step 5" << std::endl;
if (gVerboseFlag) std::cout << " JackTrip:startProcess before mAudioInterface->startProcess" << std::endl;
- mAudioInterface->startProcess();
-
- for (int i = 0; i < mProcessPlugins.size(); ++i) {
- mAudioInterface->appendProcessPlugin(mProcessPlugins[i]);
+ for (int i = 0; i < mProcessPluginsFromNetwork.size(); ++i) {
+ mAudioInterface->appendProcessPluginFromNetwork(mProcessPluginsFromNetwork[i]);
}
- if (mConnectDefaultAudioPorts) { mAudioInterface->connectDefaultPorts(); }
-}
+ for (int i = 0; i < mProcessPluginsToNetwork.size(); ++i) {
+ mAudioInterface->appendProcessPluginToNetwork(mProcessPluginsToNetwork[i]);
+ }
+ mAudioInterface->initPlugins(); // mSampleRate known now, which plugins require
+ mAudioInterface->startProcess(); // Tell JACK server we are ready for audio flow now
-//*******************************************************************************
-void JackTrip::startIOStatTimer(int timeout_sec, const std::ostream& log_stream)
-{
- mIOStatLogStream.rdbuf(log_stream.rdbuf());
- QTimer *timer = new QTimer(this);
- connect(timer, SIGNAL(timeout()), this, SLOT(onStatTimer()));
- timer->start(timeout_sec*1000);
+ if (mConnectDefaultAudioPorts) { mAudioInterface->connectDefaultPorts(); }
+
+ //Start our IO stat timer
+ if (mIOStatTimeout > 0) {
+ cout << "STATS" << mIOStatTimeout << endl;
+ if (!mIOStatStream.isNull()) {
+ mIOStatLogStream.rdbuf(((std::ostream *)mIOStatStream.data())->rdbuf());
+ }
+ QTimer *timer = new QTimer(this);
+ connect(timer, SIGNAL(timeout()), this, SLOT(onStatTimer()));
+ timer->start(mIOStatTimeout*1000);
+ }
}
//*******************************************************************************
@@ -473,11 +550,12 @@ void JackTrip::onStatTimer()
return;
}
QString now = QDateTime::currentDateTime().toString(Qt::ISODate);
- int32_t skew = recv_io_stat.underruns - recv_io_stat.overflows
- - pkt_stat.lost + pkt_stat.revived;
static QMutex mutex;
QMutexLocker locker(&mutex);
+ if (mAudioTesterP && mAudioTesterP->getEnabled()) {
+ mIOStatLogStream << "\n";
+ }
mIOStatLogStream << now.toLocal8Bit().constData()
<< " " << getPeerAddress().toLocal8Bit().constData()
<< " send: "
@@ -492,13 +570,197 @@ void JackTrip::onStatTimer()
<< "/" << pkt_stat.revived
<< " tot: "
<< pkt_stat.tot
- << " skew: " << skew
+ << " sync: "
+ << recv_io_stat.level
+ << "/" << recv_io_stat.buf_inc_underrun
+ << "/" << recv_io_stat.buf_inc_compensate
+ << "/" << recv_io_stat.buf_dec_overflows
+ << "/" << recv_io_stat.buf_dec_pktloss
+ << " skew: " << recv_io_stat.skew
+ << "/" << recv_io_stat.skew_raw
+ << " bcast: " << recv_io_stat.broadcast_skew
+ << "/" << recv_io_stat.broadcast_delta
+ << " autoq: " << 0.1*recv_io_stat.autoq_corr
+ << "/" << 0.1*recv_io_stat.autoq_rate
<< endl;
}
+void JackTrip::receivedConnectionTCP()
+{
+ mTimeoutTimer.stop();
+ if (gVerboseFlag) cout << "TCP Socket Connected to Server!" << endl;
+ emit signalTcpClientConnected();
+
+ // Send Client Port Number to Server
+ // ---------------------------------
+ char port_buf[sizeof(mReceiverBindPort) + gMaxRemoteNameLength];
+ std::memcpy(port_buf, &mReceiverBindPort, sizeof(mReceiverBindPort));
+ std::memset(port_buf + sizeof(mReceiverBindPort), 0, gMaxRemoteNameLength);
+ if (!mRemoteClientName.isEmpty()) {
+ //If our remote client name is set, send it too.
+ QByteArray name = mRemoteClientName.toUtf8();
+ // Find a clean place to truncate if we're over length.
+ // (Make sure we're not in the middle of a multi-byte characetr.)
+ int length = name.length();
+ //Need to take the final null terminator into account here.
+ if (length > gMaxRemoteNameLength - 1) {
+ length = gMaxRemoteNameLength - 1;
+ while ((length > 0) && ((name.at(length) & 0xc0) == 0x80)) {
+ //We're in the middle of a multi-byte character. Work back.
+ length--;
+ }
+ }
+ name.truncate(length);
+ std::memcpy(port_buf + sizeof(mReceiverBindPort), name.data(), length + 1);
+ }
+
+ mTcpClient.write(port_buf, sizeof(port_buf));
+ /*while ( mTcpClient.bytesToWrite() > 0 ) {
+ mTcpClient.waitForBytesWritten(-1);
+ }*/
+ if (gVerboseFlag) cout << "Port " << mReceiverBindPort << " sent to Server" << endl;
+ //Continued in receivedDataTCP slot
+}
+
+void JackTrip::receivedDataTCP()
+{
+ if (mTcpClient.bytesAvailable() < (int)sizeof(uint16_t)) {
+ return;
+ }
+
+ // Read the size of the package
+ // ----------------------------
+ if (gVerboseFlag) cout << "Reading UDP port from Server..." << endl;
+ if (gVerboseFlag) cout << "Ready To Read From Socket!" << endl;
+
+ // Read UDP Port Number from Server
+ // --------------------------------
+ uint32_t udp_port;
+ int size = sizeof(udp_port);
+ char port_buf[sizeof(mReceiverBindPort)];
+ //char port_buf[size];
+ mTcpClient.read(port_buf, size);
+ std::memcpy(&udp_port, port_buf, size);
+ //cout << "Received UDP Port Number: " << udp_port << endl;
+
+ // Close the TCP Socket
+ // --------------------
+ mTcpClient.close(); // Close the socket
+ //cout << "TCP Socket Closed!" << endl;
+ if (gVerboseFlag) cout << "Connection Succesfull!" << endl;
+
+ // Set with the received UDP port
+ // ------------------------------
+ setPeerPorts(udp_port);
+ mDataProtocolReceiver->setPeerAddress( mPeerAddress.toLatin1().data() );
+ mDataProtocolSender->setPeerAddress( mPeerAddress.toLatin1().data() );
+ mDataProtocolSender->setPeerPort(udp_port);
+ mDataProtocolReceiver->setPeerPort(udp_port);
+ cout << "Server Address set to: " << mPeerAddress.toStdString() << " Port: " << udp_port << std::endl;
+ cout << gPrintSeparator << endl;
+ completeConnection();
+}
+
+void JackTrip::receivedDataUDP()
+{
+ //Stop our timer.
+ mTimeoutTimer.stop();
+
+ QHostAddress peerHostAddress;
+ uint16_t peer_port;
+
+ // IPv6 addition from fyfe
+ // Get the datagram size to avoid problems with IPv6
+ qint64 datagramSize = mUdpSockTemp.pendingDatagramSize();
+ char buf[datagramSize];
+ // set client address
+ mUdpSockTemp.readDatagram(buf, datagramSize, &peerHostAddress, &peer_port);
+ mUdpSockTemp.close(); // close the socket
+
+ // Check for mapped IPv4->IPv6 addresses that look like ::ffff:x.x.x.x
+ if (peerHostAddress.protocol() == QAbstractSocket::IPv6Protocol) {
+ bool mappedIPv4;
+ uint32_t address = peerHostAddress.toIPv4Address(&mappedIPv4);
+ // If the IPv4 address is mapped to IPv6, convert it to IPv4
+ if (mappedIPv4) {
+ QHostAddress ipv4Address = QHostAddress(address);
+ mPeerAddress = ipv4Address.toString();
+ } else {
+ mPeerAddress = peerHostAddress.toString();
+ }
+ }
+ else {
+ mPeerAddress = peerHostAddress.toString();
+ }
+
+ // Set the peer address to send packets (in the protocol sender)
+ if (gVerboseFlag) std::cout << "JackTrip:serverStart before mDataProtocolSender->setPeerAddress()" << std::endl;
+ mDataProtocolSender->setPeerAddress( mPeerAddress.toLatin1().constData() );
+ if (gVerboseFlag) std::cout << "JackTrip:serverStart before mDataProtocolReceiver->setPeerAddress()" << std::endl;
+ mDataProtocolReceiver->setPeerAddress( mPeerAddress.toLatin1().constData() );
+ // We reply to the same port the peer sent the packets from
+ // This way we can go through NAT
+ // Because of the NAT traversal scheme, the portn need to be
+ // "symetric", e.g.:
+ // from Client to Server : src = 4474, dest = 4464
+ // from Server to Client : src = 4464, dest = 4474
+ // no -- all are the same -- 4464
+ if (gVerboseFlag) std::cout << "JackTrip:serverStart before setting all peer_port instances to " << peer_port << std::endl;
+ mDataProtocolSender->setPeerPort(peer_port);
+ mDataProtocolReceiver->setPeerPort(peer_port);
+ setPeerPorts(peer_port);
+ completeConnection();
+}
+
+void JackTrip::udpTimerTick()
+{
+ if (mStopped || sSigInt || sJackStopped) {
+ //Stop everything.
+ mUdpSockTemp.close();
+ mTimeoutTimer.stop();
+ stop();
+ }
+
+ if (gVerboseFlag) std::cout << mSleepTime << "ms " << std::flush;
+ mElapsedTime += mSleepTime;
+ if (mEndTime > 0 && mElapsedTime >= mEndTime) {
+ mUdpSockTemp.close();
+ mTimeoutTimer.stop();
+ cout << "JackTrip Server Timed Out!" << endl;
+ stop("JackTrip Server Timed Out");
+ }
+}
+
+void JackTrip::tcpTimerTick()
+{
+ if (mStopped || sSigInt || sJackStopped) {
+ //Stop everything.
+ mTcpClient.close();
+ mTimeoutTimer.stop();
+ stop();
+ }
+
+ mElapsedTime += mSleepTime;
+ if (mEndTime > 0 && mElapsedTime >= mEndTime) {
+ mTcpClient.close();
+ mTimeoutTimer.stop();
+ cout << "JackTrip Server Timed Out!" << endl;
+ stop("Initial TCP Connection Timed Out");
+ }
+
+}
+
//*******************************************************************************
-void JackTrip::stop()
+void JackTrip::stop(QString errorMessage)
{
+ mStopped = true;
+ //Make sure we're only run once
+ if (mHasShutdown) {
+ return;
+ }
+ mHasShutdown = true;
+ std::cout << "Stopping JackTrip..." << std::endl;
+
// Stop The Sender
mDataProtocolSender->stop();
mDataProtocolSender->wait();
@@ -510,12 +772,18 @@ void JackTrip::stop()
// Stop the audio processes
//mAudioInterface->stopProcess();
closeAudio();
-
+
cout << "JackTrip Processes STOPPED!" << endl;
cout << gPrintSeparator << endl;
// Emit the jack stopped signal
- emit signalProcessesStopped();
+ if (sJackStopped) {
+ emit signalError("The Jack Server was shut down!");
+ } else if (errorMessage.isEmpty()) {
+ emit signalProcessesStopped();
+ } else {
+ emit signalError(errorMessage);
+ }
}
@@ -539,6 +807,7 @@ void JackTrip::clientStart()
mDataProtocolReceiver->setPeerAddress( mPeerAddress.toLatin1().data() );
cout << "Peer Address set to: " << mPeerAddress.toStdString() << std::endl;
cout << gPrintSeparator << endl;
+ completeConnection();
}
}
@@ -555,88 +824,34 @@ int JackTrip::serverStart(bool timeout, int udpTimeout) // udpTimeout unused
}
// Get the client address when it connects
- QHostAddress peerHostAddress;
- uint16_t peer_port;
- if (gVerboseFlag) std::cout << "JackTrip:serverStart before QUdpSocket UdpSockTemp" << std::endl;
- QUdpSocket UdpSockTemp;// Create socket to wait for client
-
- if (gVerboseFlag) std::cout << "JackTrip:serverStart before UdpSockTemp.bind(Any)" << std::endl;
+ if (gVerboseFlag) std::cout << "JackTrip:serverStart before mUdpSockTemp.bind(Any)" << std::endl;
// Bind the socket
- if ( !UdpSockTemp.bind(QHostAddress::Any, mReceiverBindPort,
+ if ( !mUdpSockTemp.bind(QHostAddress::Any, mReceiverBindPort,
QUdpSocket::DefaultForPlatform) )
{
std::cerr << "in JackTrip: Could not bind UDP socket. It may be already binded." << endl;
throw std::runtime_error("Could not bind UDP socket. It may be already binded.");
}
- // Listen to client
- int sleepTime = 100; // ms
- int elapsedTime = 0;
+ connect(&mUdpSockTemp, &QUdpSocket::readyRead, this, &JackTrip::receivedDataUDP);
+
+ // Start timer and then wait for a signal to read datagrams.
+ mElapsedTime = 0;
if (timeout) {
- while ( (!UdpSockTemp.hasPendingDatagrams()) && (elapsedTime <= udpTimeout) ) {
- if (mStopped == true) { emit signalUdpTimeOut(); UdpSockTemp.close(); return -1; }
- QThread::msleep(sleepTime);
- elapsedTime += sleepTime;
- }
- if (!UdpSockTemp.hasPendingDatagrams()) {
- emit signalUdpTimeOut();
- cout << "JackTrip Server Timed Out!" << endl;
- return -1;
- }
- } else {
- if (gVerboseFlag) std::cout << "JackTrip:serverStart before !UdpSockTemp.hasPendingDatagrams()" << std::endl;
- cout << "Waiting for Connection From a Client..." << endl;
- while ( !UdpSockTemp.hasPendingDatagrams() ) {
- if (mStopped == true) { emit signalUdpTimeOut(); return -1; }
- if (gVerboseFlag) std::cout << sleepTime << "ms " << std::flush;
- QThread::msleep(sleepTime);
- }
+ mEndTime = udpTimeout;
}
+ mTimeoutTimer.setInterval(mSleepTime);
+ connect(&mTimeoutTimer, &QTimer::timeout, this, &JackTrip::udpTimerTick);
+ mTimeoutTimer.start();
+
+ if (gVerboseFlag) std::cout << "JackTrip:serverStart before !UdpSockTemp.hasPendingDatagrams()" << std::endl;
+ cout << "Waiting for Connection From a Client..." << endl;
+ return 0;
+ // Continued in the receivedDataUDP slot.
+
// char buf[1];
// // set client address
// UdpSockTemp.readDatagram(buf, 1, &peerHostAddress, &peer_port);
// UdpSockTemp.close(); // close the socket
-
- // IPv6 addition from fyfe
- // Get the datagram size to avoid problems with IPv6
- qint64 datagramSize = UdpSockTemp.pendingDatagramSize();
- char buf[datagramSize];
- // set client address
- UdpSockTemp.readDatagram(buf, datagramSize, &peerHostAddress, &peer_port);
- UdpSockTemp.close(); // close the socket
-
- // Check for mapped IPv4->IPv6 addresses that look like ::ffff:x.x.x.x
- if (peerHostAddress.protocol() == QAbstractSocket::IPv6Protocol) {
- bool mappedIPv4;
- uint32_t address = peerHostAddress.toIPv4Address(&mappedIPv4);
- // If the IPv4 address is mapped to IPv6, convert it to IPv4
- if (mappedIPv4) {
- QHostAddress ipv4Address = QHostAddress(address);
- mPeerAddress = ipv4Address.toString();
- } else {
- mPeerAddress = peerHostAddress.toString();
- }
- }
- else {
- mPeerAddress = peerHostAddress.toString();
- }
-
- // Set the peer address to send packets (in the protocol sender)
- if (gVerboseFlag) std::cout << "JackTrip:serverStart before mDataProtocolSender->setPeerAddress()" << std::endl;
- mDataProtocolSender->setPeerAddress( mPeerAddress.toLatin1().constData() );
- if (gVerboseFlag) std::cout << "JackTrip:serverStart before mDataProtocolReceiver->setPeerAddress()" << std::endl;
- mDataProtocolReceiver->setPeerAddress( mPeerAddress.toLatin1().constData() );
- // We reply to the same port the peer sent the packets from
- // This way we can go through NAT
- // Because of the NAT traversal scheme, the portn need to be
- // "symetric", e.g.:
- // from Client to Server : src = 4474, dest = 4464
- // from Server to Client : src = 4464, dest = 4474
- // no -- all are the same -- 4464
- if (gVerboseFlag) std::cout << "JackTrip:serverStart before setting all peer_port instances to " << peer_port << std::endl;
- mDataProtocolSender->setPeerPort(peer_port);
- mDataProtocolReceiver->setPeerPort(peer_port);
- setPeerPorts(peer_port);
- return 0;
}
@@ -656,7 +871,6 @@ int JackTrip::clientPingToServerStart()
// Create Socket Objects
// --------------------
- QTcpSocket tcpClient;
QHostAddress serverHostAddress;
if (!serverHostAddress.setAddress(mPeerAddress)) {
QHostInfo info = QHostInfo::fromName(mPeerAddress);
@@ -668,64 +882,18 @@ int JackTrip::clientPingToServerStart()
// Connect Socket to Server and wait for response
// ----------------------------------------------
- tcpClient.connectToHost(serverHostAddress, mTcpServerPort);
+ connect(&mTcpClient, &QTcpSocket::readyRead, this, &JackTrip::receivedDataTCP);
+ connect(&mTcpClient, &QTcpSocket::connected, this, &JackTrip::receivedConnectionTCP);
+ mElapsedTime = 0;
+ mEndTime = 5000; //Timeout after 5 seconds.
+ mTimeoutTimer.setInterval(mSleepTime);
+ connect(&mTimeoutTimer, &QTimer::timeout, this, &JackTrip::tcpTimerTick);
+ mTimeoutTimer.start();
+ mTcpClient.connectToHost(serverHostAddress, mTcpServerPort);
+
if (gVerboseFlag) cout << "Connecting to TCP Server at " << serverHostAddress.toString().toLatin1().constData() << " port " << mTcpServerPort << "..." << endl;
- if (!tcpClient.waitForConnected()) {
- std::cerr << "TCP Socket ERROR at " << mTcpServerPort << ": " << tcpClient.errorString().toStdString() << endl;
- //std::exit(1);
- return -1;
- }
- if (gVerboseFlag) cout << "TCP Socket Connected to Server!" << endl;
- emit signalTcpClientConnected();
-
- // Send Client Port Number to Server
- // ---------------------------------
- char port_buf[sizeof(mReceiverBindPort)];
- std::memcpy(port_buf, &mReceiverBindPort, sizeof(mReceiverBindPort));
-
- tcpClient.write(port_buf, sizeof(mReceiverBindPort));
- while ( tcpClient.bytesToWrite() > 0 ) {
- tcpClient.waitForBytesWritten(-1);
- }
- if (gVerboseFlag) cout << "Port " << mReceiverBindPort << " sent to Server" << endl;
-
- // Read the size of the package
- // ----------------------------
- if (gVerboseFlag) cout << "Reading UDP port from Server..." << endl;
- while (tcpClient.bytesAvailable() < (int)sizeof(uint16_t)) {
- if (!tcpClient.waitForReadyRead()) {
- std::cerr << "TCP Socket ERROR: " << tcpClient.errorString().toStdString() << endl;
- //std::exit(1);
- return -1;
- }
- }
- if (gVerboseFlag) cout << "Ready To Read From Socket!" << endl;
-
- // Read UDP Port Number from Server
- // --------------------------------
- uint32_t udp_port;
- int size = sizeof(udp_port);
- //char port_buf[size];
- tcpClient.read(port_buf, size);
- std::memcpy(&udp_port, port_buf, size);
- //cout << "Received UDP Port Number: " << udp_port << endl;
-
- // Close the TCP Socket
- // --------------------
- tcpClient.close(); // Close the socket
- //cout << "TCP Socket Closed!" << endl;
- if (gVerboseFlag) cout << "Connection Successful!" << endl;
-
- // Set with the received UDP port
- // ------------------------------
- setPeerPorts(udp_port);
- mDataProtocolReceiver->setPeerAddress( mPeerAddress.toLatin1().data() );
- mDataProtocolSender->setPeerAddress( mPeerAddress.toLatin1().data() );
- mDataProtocolSender->setPeerPort(udp_port);
- mDataProtocolReceiver->setPeerPort(udp_port);
- cout << "Server Address set to: " << mPeerAddress.toStdString() << " Port: " << udp_port << std::endl;
- cout << gPrintSeparator << endl;
return 0;
+ // Continued in the receivedConnectionTCP slot.
/*
else {
@@ -893,7 +1061,6 @@ void JackTrip::parseAudioPacket(int8_t* full_packet, int8_t* audio_packet)
std::memcpy(audio_packet, audio_part, getTotalAudioPacketSizeInBytes());
}
-
//*******************************************************************************
void JackTrip::checkPeerSettings(int8_t* full_packet)
{
diff --git a/src/JackTrip.h b/src/JackTrip.h
index 9885a21..50e90ed 100644
--- a/src/JackTrip.h
+++ b/src/JackTrip.h
@@ -44,6 +44,9 @@
#include <QObject>
#include <QString>
#include <QUdpSocket>
+#include <QTcpSocket>
+#include <QTimer>
+#include <QSharedPointer>
#include "DataProtocol.h"
#include "AudioInterface.h"
@@ -54,8 +57,9 @@
#include "PacketHeader.h"
#include "RingBuffer.h"
+#include "AudioTester.h"
-#include <signal.h>
+//#include <signal.h>
/** \brief Main class to creates a SERVER (to listen) or a CLIENT (to connect
* to a listening server) to send audio streams in the network.
*
@@ -64,7 +68,7 @@
* Classes that uses JackTrip methods need to register with it.
*/
-class JackTrip : public QThread
+class JackTrip : public QObject
{
Q_OBJECT;
@@ -80,8 +84,8 @@ public:
/// \brief Enum for the JackTrip mode
enum jacktripModeT {
- SERVER, ///< Run in Server Mode
- CLIENT, ///< Run in Client Mode
+ SERVER, ///< Run in P2P Server Mode
+ CLIENT, ///< Run in P2P Client Mode
CLIENTTOPINGSERVER, ///< Client of the Ping Server Mode
SERVERPINGSERVER ///< Server of the MultiThreaded JackTrip
};
@@ -111,7 +115,8 @@ public:
CLIENTECHO, ///< Client Echo (client self-to-self)
CLIENTFOFI, ///< Client Fan Out to Clients and Fan In from Clients (but not self-to-self)
RESERVEDMATRIX, ///< Reserved for custom patch matrix (for TUB ensemble)
- FULLMIX ///< Client Fan Out to Clients and Fan In from Clients (including self-to-self)
+ FULLMIX, ///< Client Fan Out to Clients and Fan In from Clients (including self-to-self)
+ NOAUTO ///< No automatic patching
};
//---------------------------------------------------------
@@ -133,9 +138,9 @@ public:
int BufferQueueLength = gDefaultQueueLength,
unsigned int redundancy = gDefaultRedundancy,
AudioInterface::audioBitResolutionT AudioBitResolution =
- AudioInterface::BIT16,
+ AudioInterface::BIT16,
DataProtocol::packetHeaderTypeT PacketHeaderType =
- DataProtocol::DEFAULT,
+ DataProtocol::DEFAULT,
underrunModeT UnderRunMode = WAVETABLE,
int receiver_bind_port = gDefaultPort,
int sender_bind_port = gDefaultPort,
@@ -145,20 +150,26 @@ public:
/// \brief The class destructor
virtual ~JackTrip();
+
+ static void sigIntHandler(__attribute__((unused)) int unused)
+ { std::cout << std::endl << "Shutting Down..." << std::endl; sSigInt = true; }
+ static bool sSigInt;
+ static bool sJackStopped;
/// \brief Starting point for the thread
- virtual void run() {
+ /*virtual void run() {
if (gVerboseFlag) std::cout << "Settings:startJackTrip before mJackTrip->run" << std::endl;
- }
+ }*/
/// \brief Set the Peer Address for jacktripModeT::CLIENT mode only
- virtual void setPeerAddress(const char* PeerHostOrIP);
+ virtual void setPeerAddress(QString PeerHostOrIP);
/** \brief Append a process plugin. Processes will be appended in order
* \param plugin Pointer to ProcessPlugin Class
*/
//void appendProcessPlugin(const std::tr1::shared_ptr<ProcessPlugin> plugin);
- virtual void appendProcessPlugin(ProcessPlugin* plugin);
+ virtual void appendProcessPluginToNetwork(ProcessPlugin* plugin);
+ virtual void appendProcessPluginFromNetwork(ProcessPlugin* plugin);
/// \brief Start the processing threads
virtual void startProcess(
@@ -166,9 +177,10 @@ public:
int ID
#endif // endwhere
);
+ virtual void completeConnection();
/// \brief Stop the processing threads
- virtual void stop();
+ virtual void stop(QString errorMessage = "");
/// \brief Wait for all the threads to finish. This functions is used when JackTrip is
/// run as a thread
@@ -199,12 +211,17 @@ public:
/// \brief Sets (override) Buffer Queue Length Mode after construction
virtual void setBufferQueueLength(int BufferQueueLength)
{ mBufferQueueLength = BufferQueueLength; }
+ virtual void setBufferStrategy(int BufferStrategy)
+ { mBufferStrategy = BufferStrategy; }
/// \brief Sets (override) Audio Bit Resolution after construction
virtual void setAudioBitResolution(AudioInterface::audioBitResolutionT AudioBitResolution)
{ mAudioBitResolution = AudioBitResolution; }
/// \brief Sets (override) Underrun Mode
virtual void setUnderRunMode(underrunModeT UnderRunMode)
{ mUnderRunMode = UnderRunMode; }
+ /// \brief Sets whether to quit on timeout.
+ virtual void setStopOnTimeout(bool stopOnTimeout)
+ { mStopOnTimeout = stopOnTimeout; }
/// \brief Sets port numbers for the local and peer machine.
/// Receive port is <tt>port</tt>
virtual void setAllPorts(int port)
@@ -229,9 +246,14 @@ public:
/// \brief Set Client Name to something different that the default (JackTrip)
virtual void setClientName(QString clientName)
{ mJackClientName = clientName; }
+ virtual void setRemoteClientName(QString remoteClientName)
+ { mRemoteClientName = remoteClientName; }
/// \brief Set the number of audio channels
virtual void setNumChannels(int num_chans)
{ mNumChans = num_chans; }
+
+ virtual void setIOStatTimeout(int timeout) { mIOStatTimeout = timeout; }
+ virtual void setIOStatStream(QSharedPointer<std::ofstream> statStream) { mIOStatStream = statStream; }
/// Set to connect or not default audio ports (only implemented in Jack)
virtual void setConnectDefaultAudioPorts(bool connect)
@@ -274,7 +296,9 @@ public:
{ mAudiointerfaceMode = audiointerface_mode; }
virtual void setAudioInterface(AudioInterface* const AudioInterface)
{ mAudioInterface = AudioInterface; }
-
+ virtual void setLoopBack(bool b)
+ { mLoopBack = b; }
+ virtual void setAudioTesterP(AudioTester* atp) { mAudioTesterP = atp; }
void setSampleRate(uint32_t sample_rate)
{ mSampleRate = sample_rate; }
@@ -305,6 +329,7 @@ public:
bool tcpConnectionError()
{ return mTcpConnectionError; }
+
//@}
//------------------------------------------------------------------------------------
@@ -318,13 +343,15 @@ public:
virtual int getPacketSizeInBytes();
void parseAudioPacket(int8_t* full_packet, int8_t* audio_packet);
virtual void sendNetworkPacket(const int8_t* ptrToSlot)
- { mSendRingBuffer->insertSlotNonBlocking(ptrToSlot); }
+ { mSendRingBuffer->insertSlotNonBlocking(ptrToSlot, 0, 0); }
+ virtual void receiveBroadcastPacket(int8_t* ptrToReadSlot)
+ { mReceiveRingBuffer->readBroadcastSlot(ptrToReadSlot); }
virtual void receiveNetworkPacket(int8_t* ptrToReadSlot)
{ mReceiveRingBuffer->readSlotNonBlocking(ptrToReadSlot); }
virtual void readAudioBuffer(int8_t* ptrToReadSlot)
{ mSendRingBuffer->readSlotBlocking(ptrToReadSlot); }
- virtual void writeAudioBuffer(const int8_t* ptrToSlot)
- { mReceiveRingBuffer->insertSlotNonBlocking(ptrToSlot); }
+ virtual bool writeAudioBuffer(const int8_t* ptrToSlot, int len, int lostLen)
+ { return mReceiveRingBuffer->insertSlotNonBlocking(ptrToSlot, len, lostLen); }
uint32_t getBufferSizeInSamples() const
{ return mAudioBufferSize; /*return mAudioInterface->getBufferSizeInSamples();*/ }
uint32_t getDeviceID() const
@@ -393,16 +420,21 @@ public:
void printTextTest() {std::cout << "=== JackTrip PRINT ===" << std::endl;}
void printTextTest2() {std::cout << "=== JackTrip PRINT2 ===" << std::endl;}
- void startIOStatTimer(int timeout_sec, const std::ostream& log_stream);
+ void setNetIssuesSimulation(double loss, double jitter, double delay_rel)
+ {
+ mSimulatedLossRate = loss;
+ mSimulatedJitterRate = jitter;
+ mSimulatedDelayRel = delay_rel;
+ }
+ void setBroadcast(int broadcast_queue) {mBroadcastQueueLength = broadcast_queue;}
+ void setUseRtUdpPriority(bool use) {mUseRtUdpPriority = use;}
public slots:
/// \brief Slot to stop all the processes and threads
virtual void slotStopProcesses()
- {
- std::cout << "Stopping JackTrip..." << std::endl;
- mStopped = true;
- this->stop();
- }
+ { this->stop(); }
+ virtual void slotStopProcessesDueToError(const QString &errorMessage)
+ { this->stop(errorMessage); }
/** \brief This slot emits in turn the signal signalNoUdpPacketsForSeconds
* when UDP has waited for more than 30 seconds.
@@ -414,25 +446,37 @@ public slots:
int wait_time = 10000; // msec
if ( !(wait_msec%wait_time) ) {
std::cerr << "UDP WAITED MORE THAN 10 seconds." << std::endl;
+ if (mStopOnTimeout) {
+ stop("No network data received for 10 seconds");
+ }
emit signalNoUdpPacketsForSeconds();
}
}
+ void slotUdpWaitingTooLong()
+ { emit signalUdpWaitingTooLong(); }
void slotPrintTest()
{ std::cout << "=== TESTING ===" << std::endl; }
void slotReceivedConnectionFromPeer()
- { mReceivedConnection = true; }
+ { mReceivedConnection = true; emit signalReceivedConnectionFromPeer(); }
void onStatTimer();
-
+
+private slots:
+ void receivedConnectionTCP();
+ void receivedDataTCP();
+ void receivedDataUDP();
+ void udpTimerTick();
+ void tcpTimerTick();
signals:
-
- void signalUdpTimeOut();
+ //void signalUdpTimeOut();
/// \brief Signal emitted when all the processes and threads are stopped
void signalProcessesStopped();
/// \brief Signal emitted when no UDP Packets have been received for a while
void signalNoUdpPacketsForSeconds();
void signalTcpClientConnected();
-
+ void signalError(const QString &errorMessage);
+ void signalReceivedConnectionFromPeer();
+ void signalUdpWaitingTooLong();
public:
@@ -475,10 +519,13 @@ private:
int mNumNetRevChans; ///< Number of Network Audio Channels (net comb filters)
#endif // endwhere
int mBufferQueueLength; ///< Audio Buffer from network queue length
+ int mBufferStrategy;
+ int mBroadcastQueueLength;
uint32_t mSampleRate; ///< Sample Rate
uint32_t mDeviceID; ///< RTAudio DeviceID
uint32_t mAudioBufferSize; ///< Audio buffer size to process on each callback
AudioInterface::audioBitResolutionT mAudioBitResolution; ///< Audio Bit Resolutions
+ bool mLoopBack;
QString mPeerAddress; ///< Peer Address to use in jacktripModeT::CLIENT Mode
/// Pointer to Abstract Type DataProtocol that sends packets
@@ -488,6 +535,7 @@ private:
AudioInterface* mAudioInterface; ///< Interface to Jack Client
PacketHeader* mPacketHeader; ///< Pointer to Packet Header
underrunModeT mUnderRunMode; ///< underrunModeT Mode
+ bool mStopOnTimeout; ///< Stop on 10 second timeout
/// Pointer for the Send RingBuffer
RingBuffer* mSendRingBuffer;
@@ -502,18 +550,36 @@ private:
unsigned int mRedundancy; ///< Redundancy factor in network data
QString mJackClientName; ///< JackAudio Client Name
+ QString mRemoteClientName; ///< Remote JackAudio Client Name for hub client mode
JackTrip::connectionModeT mConnectionMode; ///< Connection Mode
JackTrip::hubConnectionModeT mHubConnectionModeT; ///< Hub Server Jack Audio Patch Connection Mode
- QVector<ProcessPlugin*> mProcessPlugins; ///< Vector of ProcesPlugin<EM>s</EM>
+ QVector<ProcessPlugin*> mProcessPluginsFromNetwork; ///< Vector of ProcessPlugin<EM>s</EM>
+ QVector<ProcessPlugin*> mProcessPluginsToNetwork; ///< Vector of ProcessPlugin<EM>s</EM>
+
+ QTimer mTimeoutTimer;
+ int mSleepTime;
+ int mElapsedTime;
+ int mEndTime;
+ QTcpSocket mTcpClient;
+ QUdpSocket mUdpSockTemp;
volatile bool mReceivedConnection; ///< Bool of received connection from peer
volatile bool mTcpConnectionError;
volatile bool mStopped;
+ volatile bool mHasShutdown;
bool mConnectDefaultAudioPorts; ///< Connect or not default audio ports
+ QSharedPointer<std::ofstream> mIOStatStream;
+ int mIOStatTimeout;
std::ostream mIOStatLogStream;
+ double mSimulatedLossRate;
+ double mSimulatedJitterRate;
+ double mSimulatedDelayRel;
+ bool mUseRtUdpPriority;
+
+ AudioTester* mAudioTesterP;
};
#endif
diff --git a/src/JackTripThread.cpp b/src/JackTripThread.cpp
index abe1e9c..bcaeaf0 100644
--- a/src/JackTripThread.cpp
+++ b/src/JackTripThread.cpp
@@ -57,14 +57,14 @@ void JackTripThread::run()
}
NetKS netks;
- jacktrip.appendProcessPlugin(&netks);
+ jacktrip.appendProcessPluginFromNetwork(&netks);
//netks.play();
//QThread::sleep(1);
- jacktrip.start();
+ //jacktrip.start();
//netks.play();
- jacktrip.wait();
+ //jacktrip.wait();
cout << "******** AFTER JACKTRIPTHREAD START **************" << endl;
diff --git a/src/JackTripWorker.cpp b/src/JackTripWorker.cpp
index f006261..995c4a2 100644
--- a/src/JackTripWorker.cpp
+++ b/src/JackTripWorker.cpp
@@ -45,7 +45,7 @@
#include "JackTripWorker.h"
#include "JackTrip.h"
#include "UdpHubListener.h"
-#include "NetKS.h"
+//#include "NetKS.h"
#include "LoopBack.h"
#include "Settings.h"
#ifdef WAIR // wair
@@ -58,14 +58,16 @@
using std::cout; using std::endl;
//*******************************************************************************
-JackTripWorker::JackTripWorker(UdpHubListener* udpmasterlistener, int BufferQueueLength, JackTrip::underrunModeT UnderRunMode) :
- mUdpHubListener(udpmasterlistener),
+JackTripWorker::JackTripWorker(UdpHubListener* udphublistener, int BufferQueueLength, JackTrip::underrunModeT UnderRunMode, QString clientName) :
+ mUdpHubListener(udphublistener),
m_connectDefaultAudioPorts(false),
mBufferQueueLength(BufferQueueLength),
mUnderRunMode(UnderRunMode),
+ mClientName(clientName),
mSpawning(false),
mID(0),
- mNumChans(1)
+ mNumChans(1),
+ mIOStatTimeout(0)
#ifdef WAIR // wair
,mNumNetRevChans(0),
mWAIR(false)
@@ -74,6 +76,12 @@ JackTripWorker::JackTripWorker(UdpHubListener* udpmasterlistener, int BufferQueu
setAutoDelete(false); // stick around after calling run()
//mNetks = new NetKS;
//mNetks->play();
+ mBufferStrategy = 1;
+ mBroadcastQueue = 0;
+ mSimulatedLossRate = 0.0;
+ mSimulatedJitterRate = 0.0;
+ mSimulatedDelayRel = 0.0;
+ mUseRtUdpPriority = false;
}
@@ -128,7 +136,6 @@ void JackTripWorker::run()
// Create and setup JackTrip Object
//JackTrip jacktrip(JackTrip::SERVER, JackTrip::UDP, mNumChans, 2);
if (gVerboseFlag) cout << "---> JackTripWorker: Creating jacktrip objects..." << endl;
- Settings* settings = mUdpHubListener->getSettings();
#ifdef WAIR // WAIR
// forces BufferQueueLength to 2
@@ -162,7 +169,7 @@ void JackTripWorker::run()
switch ( mNumNetRevChans )
{
case 16 : // freeverb
- mJackTrip->appendProcessPlugin(new dcblock2gain(mNumChans)); // plugin slot 0
+ mJackTrip->appendProcessPluginFromNetwork(new dcblock2gain(mNumChans)); // plugin slot 0
///////////////
// mJackTrip->appendProcessPlugin(new comb16server(mNumNetChans));
// -S LAIR no AP mJackTrip->appendProcessPlugin(new AP8(mNumChans));
@@ -184,6 +191,14 @@ void JackTripWorker::run()
// Set our underrun mode
jacktrip.setUnderRunMode(mUnderRunMode);
+ if (mIOStatTimeout > 0) {
+ jacktrip.setIOStatTimeout(mIOStatTimeout);
+ jacktrip.setIOStatStream(mIOStatStream);
+ }
+
+ if (!mClientName.isEmpty()) {
+ jacktrip.setClientName(mClientName);
+ }
// Connect signals and slots
// -------------------------
@@ -195,6 +210,7 @@ void JackTripWorker::run()
// Connection to terminate the local eventloop when jacktrip is done
QObject::connect(&jacktrip, SIGNAL(signalProcessesStopped()),
&event_loop, SLOT(quit()), Qt::QueuedConnection);
+ QObject::connect(&jacktrip, &JackTrip::signalError, &event_loop, &QEventLoop::quit, Qt::QueuedConnection);
QObject::connect(this, SIGNAL(signalRemoveThread()),
&jacktrip, SLOT(slotStopProcesses()), Qt::QueuedConnection);
@@ -203,9 +219,14 @@ void JackTripWorker::run()
// I still haven't figure out why
//ClientAddress.toString().toLatin1().constData();
//jacktrip.setPeerAddress(ClientAddress.toString().toLatin1().constData());
- jacktrip.setPeerAddress(mClientAddress.toLatin1().constData());
+ jacktrip.setPeerAddress(mClientAddress);
jacktrip.setBindPorts(mServerPort);
//jacktrip.setPeerPorts(mClientPort);
+ jacktrip.setBufferStrategy(mBufferStrategy);
+ jacktrip.setNetIssuesSimulation(mSimulatedLossRate,
+ mSimulatedJitterRate, mSimulatedDelayRel);
+ jacktrip.setBroadcast(mBroadcastQueue);
+ jacktrip.setUseRtUdpPriority(mUseRtUdpPriority);
if (gVerboseFlag) cout << "---> JackTripWorker: setJackTripFromClientHeader..." << endl;
int PeerConnectionMode = setJackTripFromClientHeader(jacktrip);
@@ -222,9 +243,6 @@ void JackTripWorker::run()
mID
#endif // endwhere
);
- if (0 != settings->getIOStatTimeout()) {
- jacktrip.startIOStatTimer(settings->getIOStatTimeout(), settings->getIOStatStream());
- }
// if (gVerboseFlag) cout << "---> JackTripWorker: start..." << endl;
// jacktrip.start(); // ########### JamTest Only #################
@@ -233,11 +251,11 @@ void JackTripWorker::run()
event_loop.exec(); // Excecution will block here until exit() the QEventLoop
//--------------------------------------------------------------------------
-
+
{ QMutexLocker locker(&mMutex); mSpawning = true; }
// wait for jacktrip to be done before exiting the Worker Thread
- jacktrip.wait();
+ //jacktrip.wait();
}
catch ( const std::exception & e )
diff --git a/src/JackTripWorker.h b/src/JackTripWorker.h
index 62c65da..98524cf 100644
--- a/src/JackTripWorker.h
+++ b/src/JackTripWorker.h
@@ -70,7 +70,7 @@ class JackTripWorker : public QObject, public QRunnable
public:
/// \brief The class constructor
- JackTripWorker(UdpHubListener* udpmasterlistener, int BufferQueueLength = gDefaultQueueLength, JackTrip::underrunModeT UnderRunMode = JackTrip::WAVETABLE);
+ JackTripWorker(UdpHubListener* udphublistener, int BufferQueueLength = gDefaultQueueLength, JackTrip::underrunModeT UnderRunMode = JackTrip::WAVETABLE, QString clientName = "");
/// \brief The class destructor
virtual ~JackTripWorker();
@@ -97,7 +97,19 @@ public:
return mID;
}
-
+ void setBufferStrategy(int BufferStrategy) { mBufferStrategy = BufferStrategy; }
+ void setNetIssuesSimulation(double loss, double jitter, double delay_rel)
+ {
+ mSimulatedLossRate = loss;
+ mSimulatedJitterRate = jitter;
+ mSimulatedDelayRel = delay_rel;
+ }
+ void setBroadcast(int broadcast_queue) {mBroadcastQueue = broadcast_queue;}
+ void setUseRtUdpPriority(bool use) {mUseRtUdpPriority = use;}
+
+ void setIOStatTimeout(int timeout) { mIOStatTimeout = timeout; }
+ void setIOStatStream(QSharedPointer<std::ofstream> statStream) { mIOStatStream = statStream; }
+
private slots:
void slotTest()
{ std::cout << "--- JackTripWorker TEST SLOT ---" << std::endl; }
@@ -106,7 +118,6 @@ private slots:
signals:
void signalRemoveThread();
-
private:
int setJackTripFromClientHeader(JackTrip& jacktrip);
JackTrip::connectionModeT getConnectionModeFromHeader();
@@ -119,16 +130,28 @@ private:
/// Client Outgoing Port. By convention, the receving port will be <tt>mClientPort -1</tt>
uint16_t mClientPort;
+
+ int mBufferQueueLength;
+ JackTrip::underrunModeT mUnderRunMode;
+ QString mClientName;
/// Thread spawning internal lock.
/// If true, the prototype is working on creating (spawning) a new thread
volatile bool mSpawning;
QMutex mMutex; ///< Mutex to protect mSpawning
- JackTrip::underrunModeT mUnderRunMode;
- int mBufferQueueLength;
int mID; ///< ID thread number
int mNumChans; ///< Number of Channels
+
+ int mBufferStrategy;
+ int mBroadcastQueue;
+ double mSimulatedLossRate;
+ double mSimulatedJitterRate;
+ double mSimulatedDelayRel;
+ bool mUseRtUdpPriority;
+
+ int mIOStatTimeout;
+ QSharedPointer<std::ofstream> mIOStatStream;
#ifdef WAIR // wair
int mNumNetRevChans; ///< Number of Net Channels = net combs
bool mWAIR;
diff --git a/src/JitterBuffer.cpp b/src/JitterBuffer.cpp
new file mode 100644
index 0000000..9f73d53
--- /dev/null
+++ b/src/JitterBuffer.cpp
@@ -0,0 +1,389 @@
+//*****************************************************************
+/*
+ JackTrip: A System for High-Quality Audio Network Performance
+ over the Internet
+
+ Copyright (c) 2020 Juan-Pablo Caceres, Chris Chafe.
+ SoundWIRE group at CCRMA, Stanford University.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+*/
+//*****************************************************************
+
+/**
+ * \file JitterBuffer.cpp
+ * \author Anton Runov
+ * \date June 2020
+ */
+
+
+#include "JitterBuffer.h"
+
+#include <iostream>
+#include <cstring>
+#include <cstdlib>
+#include <stdexcept>
+#include <cmath>
+
+using std::cout; using std::endl;
+
+
+//*******************************************************************************
+JitterBuffer::JitterBuffer(int buf_samples, int qlen, int sample_rate, int strategy,
+ int bcast_qlen, int channels, int bit_res) :
+ RingBuffer(0, 0)
+{
+ int total_size = sample_rate * channels * bit_res * 2; // 2 secs of audio
+ int slot_size = buf_samples * channels * bit_res;
+ mSlotSize = slot_size;
+ mInSlotSize = slot_size;
+ if (0 < qlen) {
+ mMaxLatency = qlen * slot_size;
+ mAutoQueue = 0;
+ }
+ else {
+ // AutoQueue
+ mMaxLatency = 3*slot_size;
+ mAutoQueue = 1;
+ }
+ mTotalSize = total_size;
+ mBroadcastLatency = bcast_qlen * mSlotSize;
+ mNumChannels = channels;
+ mAudioBitRes = bit_res;
+ mMinStepSize = channels * bit_res;
+ mFPP = buf_samples;
+ mSampleRate = sample_rate;
+ mActive = false;
+
+ // Defaults for zero strategy
+ mUnderrunIncTolerance = -10 * mSlotSize;
+ mCorrIncTolerance = 100*mMaxLatency; // should be greater than mUnderrunIncTolerance
+ mOverflowDecTolerance = 100*mMaxLatency;
+ mWritePosition = mMaxLatency;
+ mStatUnit = mSlotSize;
+ mLevelDownRate = std::min(256, mFPP) / (5.0*sample_rate) * mSlotSize;
+ mOverflowDropStep = mMaxLatency / 2;
+ mLevelCur = mMaxLatency;
+ mLevel = mLevelCur;
+ mMinLevelThreshold = 1.9 * mSlotSize;
+ mBroadcastPosition = 0;
+ mBroadcastPositionCorr = 0.0;
+ mLastCorrCounter = 0;
+ mLastCorrDirection = 0;
+
+ switch (strategy) {
+ case 1:
+ mOverflowDropStep = mSlotSize;
+ break;
+ case 2:
+ mUnderrunIncTolerance = 1.1 * mSlotSize;
+ mCorrIncTolerance = 1.9 * mSlotSize; // should be greater than mUnderrunIncTolerance
+ mOverflowDecTolerance = 0.1*mSlotSize;
+ mOverflowDropStep = mSlotSize;
+ break;
+ }
+
+ mRingBuffer = new int8_t[mTotalSize];
+ std::memset(mRingBuffer, 0, mTotalSize);
+
+ mAutoQueueCorr = 2*mSlotSize;
+ if (0 > qlen) {
+ mAutoQFactor = 1.0/-qlen;
+ }
+ else {
+ mAutoQFactor = 1.0/500;
+ }
+ mAutoQRate = mSlotSize * 0.5;
+ mAutoQRateMin = mSlotSize * 0.0005;
+ mAutoQRateDecay = 1.0 - std::min(mFPP*1.2e-6, 0.0005);
+}
+
+//*******************************************************************************
+bool JitterBuffer::insertSlotNonBlocking(const int8_t* ptrToSlot, int len, int lostLen)
+{
+ if (0 == len) {
+ len = mSlotSize;
+ }
+ QMutexLocker locker(&mMutex);
+ mInSlotSize = len;
+ if (!mActive) {
+ mActive = true;
+ }
+ if (mMaxLatency < len + mSlotSize) {
+ mMaxLatency = len + mSlotSize;
+ }
+ if (0 < lostLen) {
+ processPacketLoss(lostLen);
+ }
+ mSkewRaw += mReadsNew - len;
+ mReadsNew = 0;
+ mUnderruns += mUnderrunsNew;
+ mUnderrunsNew = 0;
+ mLevel = mSlotSize*std::ceil(mLevelCur/mSlotSize);
+
+ // Update positions if necessary
+ int32_t available = mWritePosition - mReadPosition;
+
+ int delta = 0;
+ if (available < -10*mMaxLatency) {
+ delta = available;
+ mBufIncUnderrun += -delta;
+ mLevelCur = len;
+ //cout << "reset" << endl;
+ }
+ else if (available + len > mMaxLatency) {
+ delta = mOverflowDropStep;
+ mOverflows += delta;
+ mBufDecOverflow += delta;
+ mLevelCur = mMaxLatency;
+ }
+ else if (0 > available &&
+ mLevelCur < std::max(mInSlotSize + mMinLevelThreshold,
+ mMaxLatency - mUnderrunIncTolerance - 2*mSlotSize*lastCorrFactor())) {
+ delta = -std::min(-available, mSlotSize);
+ mBufIncUnderrun += -delta;
+ }
+ else if (mLevelCur < mMaxLatency - mCorrIncTolerance - 6*mSlotSize*lastCorrFactor()) {
+ delta = -mSlotSize;
+ mUnderruns += -delta;
+ mBufIncCompensate += -delta;
+ }
+
+ if (0 != delta) {
+ mReadPosition += delta;
+ mLastCorrCounter = 0;
+ mLastCorrDirection = 0 < delta ? 1 : -1;
+ }
+ else {
+ ++mLastCorrCounter;
+ }
+
+ int wpos = mWritePosition % mTotalSize;
+ int n = std::min(mTotalSize - wpos, len);
+ std::memcpy(mRingBuffer+wpos, ptrToSlot, n);
+ if (n < len) {
+ //cout << "split write: " << len << "-" << n << endl;
+ std::memcpy(mRingBuffer, ptrToSlot+n, len-n);
+ }
+ mWritePosition += len;
+
+ return true;
+}
+
+//*******************************************************************************
+void JitterBuffer::readSlotNonBlocking(int8_t* ptrToReadSlot)
+{
+ int len = mSlotSize;
+ QMutexLocker locker(&mMutex);
+ if (!mActive) {
+ std::memset(ptrToReadSlot, 0, len);
+ return;
+ }
+ mReadsNew += len;
+ int32_t available = mWritePosition - mReadPosition;
+ if (available < mLevelCur) {
+ mLevelCur = std::max((double)available, mLevelCur-mLevelDownRate);
+ }
+ else {
+ mLevelCur = available;
+ }
+
+ // auto queue correction
+ if (0 > available + mAutoQueueCorr - mLevelCur) {
+ mAutoQueueCorr += mAutoQRate;
+ }
+ else if (mInSlotSize + mSlotSize < mAutoQueueCorr) {
+ mAutoQueueCorr -= mAutoQRate * mAutoQFactor;
+ }
+ if (mAutoQRate > mAutoQRateMin) {
+ mAutoQRate *= mAutoQRateDecay;
+ }
+ if (0 != mAutoQueue) {
+ int PPS = mSampleRate / mFPP;
+ if (2*PPS == mAutoQueue++ % (4*PPS)) {
+ double k = 1.0 + 1e-5/mAutoQFactor;
+ if (12*PPS > mAutoQueue ||
+ std::abs(mAutoQueueCorr*k - mMaxLatency + mSlotSize/2) > 0.6*mSlotSize) {
+ mMaxLatency = mSlotSize * std::ceil(mAutoQueueCorr*k/mSlotSize);
+ cout << "AutoQueue: " << mMaxLatency / mSlotSize << endl;
+ }
+ }
+ }
+
+ int read_len = qBound(0, available, len);
+ int rpos = mReadPosition % mTotalSize;
+ int n = std::min(mTotalSize - rpos, read_len);
+ std::memcpy(ptrToReadSlot, mRingBuffer+rpos, n);
+ if (n < read_len) {
+ //cout << "split read: " << read_len << "-" << n << endl;
+ std::memcpy(ptrToReadSlot+n, mRingBuffer, read_len-n);
+ }
+ if (read_len < len) {
+ std::memset(ptrToReadSlot+read_len, 0, len-read_len);
+ mUnderrunsNew += len-read_len;
+ }
+ mReadPosition += len;
+}
+
+//*******************************************************************************
+void JitterBuffer::readBroadcastSlot(int8_t* ptrToReadSlot)
+{
+ int len = mSlotSize;
+ QMutexLocker locker(&mMutex);
+ if (mBroadcastLatency + len > mReadPosition) {
+ std::memset(ptrToReadSlot, 0, len);
+ return;
+ }
+ // latency correction
+ int32_t d = mReadPosition - mBroadcastLatency - mBroadcastPosition - len;
+ if (std::abs(d) > mBroadcastLatency / 2) {
+ mBroadcastPosition = mReadPosition - mBroadcastLatency - len;
+ mBroadcastPositionCorr = 0.0;
+ mBroadcastSkew += d / mMinStepSize;
+ }
+ else {
+ mBroadcastPositionCorr += 0.0003 * d;
+ int delta = mBroadcastPositionCorr / mMinStepSize;
+ if (0 != delta) {
+ mBroadcastPositionCorr -= delta * mMinStepSize;
+ if (2 == mAudioBitRes && (int32_t)(mWritePosition - mBroadcastPosition) > len) {
+ // interpolate
+ len += delta * mMinStepSize;
+ }
+ else {
+ // skip
+ mBroadcastPosition += delta * mMinStepSize;
+ }
+ mBroadcastSkew += delta;
+ }
+ }
+ mBroadcastDelta = d / mMinStepSize;
+ int32_t available = mWritePosition - mBroadcastPosition;
+ int read_len = qBound(0, available, len);
+ if (len == mSlotSize) {
+ int rpos = mBroadcastPosition % mTotalSize;
+ int n = std::min(mTotalSize - rpos, read_len);
+ std::memcpy(ptrToReadSlot, mRingBuffer+rpos, n);
+ if (n < read_len) {
+ //cout << "split read: " << read_len << "-" << n << endl;
+ std::memcpy(ptrToReadSlot+n, mRingBuffer, read_len-n);
+ }
+ if (read_len < len) {
+ std::memset(ptrToReadSlot+read_len, 0, len-read_len);
+ }
+ }
+ else {
+ // interpolation len => mSlotSize
+ double K = 1.0 * len / mSlotSize;
+ for (int c=0; c < mMinStepSize; c+=sizeof(int16_t)) {
+ for (int j=0; j < mSlotSize/mMinStepSize; ++j) {
+ int j1 = std::floor(j*K);
+ double a = j*K - j1;
+ int rpos = (mBroadcastPosition + j1*mMinStepSize + c) % mTotalSize;
+ int16_t v1 = *(int16_t*)(mRingBuffer + rpos);
+ rpos = (rpos + mMinStepSize) % mTotalSize;
+ int16_t v2 = *(int16_t*)(mRingBuffer + rpos);
+ *(int16_t*)(ptrToReadSlot + j*mMinStepSize + c) = std::round((1-a)*v1 + a*v2);
+ }
+ }
+ }
+ mBroadcastPosition += len;
+}
+
+
+//*******************************************************************************
+void JitterBuffer::processPacketLoss(int lostLen)
+{
+ mSkewRaw -= lostLen;
+
+ int32_t available = mWritePosition - mReadPosition;
+ int delta = std::min(available + mInSlotSize + lostLen - mMaxLatency, lostLen);
+ if (0 < delta) {
+ lostLen -= delta;
+ mBufDecPktLoss += delta;
+ mLevelCur = mMaxLatency;
+ mLastCorrCounter = 0;
+ mLastCorrDirection = 1;
+ }
+ else if (mSlotSize < available + lostLen && (
+ mOverflowDecTolerance > mMaxLatency // for strategies 0,1
+ || (0 < mLastCorrDirection && mLevelCur >
+ mMaxLatency - mOverflowDecTolerance*(1.1 - lastCorrFactor()))
+ )) {
+ delta = std::min(lostLen, mSlotSize);
+ lostLen -= delta;
+ mBufDecPktLoss += delta;
+ mLevelCur -= delta;
+ mLastCorrCounter = 0;
+ mLastCorrDirection = 1;
+ }
+ if (lostLen >= mTotalSize) {
+ std::memset(mRingBuffer, 0, mTotalSize);
+ mUnderruns += std::max(0, lostLen - std::max(0, -available));
+ }
+ else if (0 < lostLen) {
+ int wpos = mWritePosition % mTotalSize;
+ int n = std::min(mTotalSize - wpos, lostLen);
+ std::memset(mRingBuffer+wpos, 0, n);
+ if (n < lostLen) {
+ //cout << "split write: " << lostLen << "-" << n << endl;
+ std::memset(mRingBuffer, 0, lostLen-n);
+ }
+ mUnderruns += std::max(0, lostLen - std::max(0, -available));
+ }
+ mWritePosition += lostLen;
+}
+
+//*******************************************************************************
+bool JitterBuffer::getStats(RingBuffer::IOStat* stat, bool reset)
+{
+ QMutexLocker locker(&mMutex);
+ if (reset) {
+ mUnderruns = 0;
+ mOverflows = 0;
+ mSkew0 = mLevel;
+ mSkewRaw = 0;
+ mBufDecOverflow = 0;
+ mBufDecPktLoss = 0;
+ mBufIncUnderrun = 0;
+ mBufIncCompensate = 0;
+ mBroadcastSkew = 0;
+ }
+ stat->underruns = mUnderruns / mStatUnit;
+ stat->overflows = mOverflows / mStatUnit;
+ stat->skew = (int32_t)((mSkew0 - mLevel + mBufIncUnderrun + mBufIncCompensate
+ - mBufDecOverflow - mBufDecPktLoss)) / mStatUnit;
+ stat->skew_raw = mSkewRaw / mStatUnit;
+ stat->level = mLevel / mStatUnit;
+
+ stat->buf_dec_overflows = mBufDecOverflow / mStatUnit;
+ stat->buf_dec_pktloss = mBufDecPktLoss / mStatUnit;
+ stat->buf_inc_underrun = mBufIncUnderrun / mStatUnit;
+ stat->buf_inc_compensate = mBufIncCompensate / mStatUnit;
+ stat->broadcast_skew = mBroadcastSkew;
+ stat->broadcast_delta = mBroadcastDelta;
+
+ stat->autoq_corr = mAutoQueueCorr / mStatUnit * 10;
+ stat->autoq_rate = mAutoQRate / mStatUnit * 1000;
+ return true;
+}
+
diff --git a/src/JitterBuffer.h b/src/JitterBuffer.h
new file mode 100644
index 0000000..6be4069
--- /dev/null
+++ b/src/JitterBuffer.h
@@ -0,0 +1,90 @@
+//*****************************************************************
+/*
+ JackTrip: A System for High-Quality Audio Network Performance
+ over the Internet
+
+ Copyright (c) 2020 Juan-Pablo Caceres, Chris Chafe.
+ SoundWIRE group at CCRMA, Stanford University.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+*/
+//*****************************************************************
+
+/**
+ * \file JitterBuffer.h
+ * \author Anton Runov
+ * \date June 2020
+ */
+
+#ifndef __JITTERBUFFER_H__
+#define __JITTERBUFFER_H__
+
+#include "RingBuffer.h"
+
+class JitterBuffer : public RingBuffer
+{
+public:
+ JitterBuffer(int buf_samples, int qlen, int sample_rate, int strategy,
+ int bcast_qlen, int channels, int bit_res);
+ virtual ~JitterBuffer() {}
+
+ virtual bool insertSlotNonBlocking(const int8_t* ptrToSlot, int len, int lostLen);
+ virtual void readSlotNonBlocking(int8_t* ptrToReadSlot);
+ virtual void readBroadcastSlot(int8_t* ptrToReadSlot);
+
+ virtual bool getStats(IOStat* stat, bool reset);
+
+protected:
+ void processPacketLoss(int lostLen);
+
+protected:
+ int mMaxLatency;
+ int mNumChannels;
+ int mAudioBitRes;
+ int mMinStepSize;
+ int mFPP;
+ int mSampleRate;
+ int mInSlotSize;
+ bool mActive;
+ uint32_t mBroadcastLatency;
+ uint32_t mBroadcastPosition;
+ double mBroadcastPositionCorr;
+
+ double mUnderrunIncTolerance;
+ double mCorrIncTolerance;
+ double mOverflowDecTolerance;
+ int mOverflowDropStep;
+ uint32_t mLastCorrCounter;
+ int mLastCorrDirection;
+ double mMinLevelThreshold;
+ double lastCorrFactor() const {return 500.0 / std::max(500U, mLastCorrCounter);}
+
+ int mAutoQueue;
+ double mAutoQueueCorr;
+ double mAutoQFactor;
+ double mAutoQRate;
+ double mAutoQRateMin;
+ double mAutoQRateDecay;
+};
+
+
+#endif //__JITTERBUFFER_H__
diff --git a/src/Limiter.cpp b/src/Limiter.cpp
new file mode 100644
index 0000000..91a918f
--- /dev/null
+++ b/src/Limiter.cpp
@@ -0,0 +1,71 @@
+//*****************************************************************
+/*
+ JackTrip: A System for High-Quality Audio Network Performance
+ over the Internet
+
+ Copyright (c) 2020 Julius Smith, Juan-Pablo Caceres, Chris Chafe.
+ SoundWIRE group at CCRMA, Stanford University.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+*/
+//*****************************************************************
+
+/**
+ * \file Limiter.cpp
+ * \author Julius Smith, based on LoopBack.h
+ * \date May-Nov 2020
+ * \license MIT
+ */
+
+#include "Limiter.h"
+#include "jacktrip_types.h"
+
+#include <iostream>
+
+//*******************************************************************************
+void Limiter::compute(int nframes, float** inputs, float** outputs)
+{
+ if (not inited) {
+ std::cerr << "*** Limiter " << this << ": init never called! Doing it now.\n";
+ if (fSamplingFreq <= 0) {
+ fSamplingFreq = 48000;
+ std::cout << "Limiter " << this << ": *** HAD TO GUESS the sampling rate (chose 48000 Hz) ***\n";
+ }
+ init(fSamplingFreq);
+ }
+#ifdef SINE_TEST
+ float sineTestOut[nframes];
+ float* faustSigs[1] { sineTestOut };
+#endif
+ for ( int i = 0; i < mNumChannels; i++ ) {
+ if (warningAmp > 0.0) {
+ checkAmplitudes(nframes, inputs[i]); // we presently do one check across all channels
+ }
+ limiterP[i]->compute(nframes, &inputs[i], &outputs[i]);
+#ifdef SINE_TEST
+ limiterTestP[i]->compute(nframes, faustSigs, faustSigs);
+ for ( int n = 0; n < nframes; n++ ) {
+ outputs[i][n] = outputs[i][n] + sineTestOut[n];
+ }
+#endif
+ }
+}
diff --git a/src/Limiter.h b/src/Limiter.h
new file mode 100644
index 0000000..6318d22
--- /dev/null
+++ b/src/Limiter.h
@@ -0,0 +1,179 @@
+//*****************************************************************
+/*
+ JackTrip: A System for High-Quality Audio Network Performance
+ over the Internet
+
+ Copyright (c) 2020 Julius Smith, Juan-Pablo Caceres, Chris Chafe.
+ SoundWIRE group at CCRMA, Stanford University.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+*/
+//*****************************************************************
+
+/**
+ * \file Limiter.h
+ * \author Julius Smith, based on LoopBack.h
+ * \date May-Nov 2020
+ * \license MIT
+ */
+
+/** \brief Applies limiter_lad_mono from the faustlibraries distribution, compressors.lib
+ *
+ */
+#ifndef __LIMITER_H__
+#define __LIMITER_H__
+
+//#define SINE_TEST
+
+#ifdef SINE_TEST
+#include "limitertest.h"
+#endif
+
+#include "ProcessPlugin.h"
+#include "limiterdsp.h"
+#include <vector>
+#include "assert.h"
+
+/** \brief The Limiter class confines the output dynamic range to a
+ * "dynamic range lane" determined by the assumed number of clients.
+ */
+class Limiter : public ProcessPlugin
+{
+public:
+ /// \brief The class constructor sets the number of channels to limit
+ Limiter(int numchans, int numclients, bool verboseFlag = false) // xtor
+ : mNumChannels(numchans), mNumClients(numclients)
+ , warningAmp(0.0), warnCount(0), peakMagnitude(0.0), nextWarning(1)
+ {
+ setVerbose(verboseFlag);
+ for ( int i = 0; i < mNumChannels; i++ ) {
+ limiterP.push_back(new limiterdsp);
+ limiterUIP.push_back(new APIUI); // #included in limiterdsp.h
+ limiterP[i]->buildUserInterface(limiterUIP[i]);
+#ifdef SINE_TEST
+ limiterTestP.push_back(new limitertest);
+ limiterTestUIP.push_back(new APIUI); // #included in limitertest.h
+ limiterTestP[i]->buildUserInterface(limiterTestUIP[i]);
+#endif
+ }
+ // std::cout << "Limiter: constructed for "
+ // << mNumChannels << " channels and "
+ // << mNumClients << " assumed clients\n";
+ }
+
+ /// \brief The class destructor
+ virtual ~Limiter() {
+ for ( int i = 0; i < mNumChannels; i++ ) {
+ delete limiterP[i];
+ delete limiterUIP[i];
+ }
+ limiterP.clear();
+ limiterUIP.clear();
+ }
+
+ void init(int samplingRate) override {
+ ProcessPlugin::init(samplingRate);
+ if (samplingRate != fSamplingFreq) {
+ std::cerr << "Sampling rate not set by superclass!\n";
+ std::exit(1); }
+ fs = float(fSamplingFreq);
+ for ( int i = 0; i < mNumChannels; i++ ) {
+ limiterP[i]->init(fs); // compression filter parameters depend on sampling rate
+ int ndx = limiterUIP[i]->getParamIndex("NumClientsAssumed");
+ limiterUIP[i]->setParamValue(ndx, mNumClients);
+#ifdef SINE_TEST
+ limiterTestP[i]->init(fs); // oscillator parameters depend on sampling rate
+ ndx = limiterTestUIP[i]->getParamIndex("Amp");
+ limiterTestUIP[i]->setParamValue(ndx, 0.2);
+ ndx = limiterTestUIP[i]->getParamIndex("Freq");
+ float sineFreq = 110.0 * pow(1.5,double(i)) * (mNumClients>1?1.25:1.0); // Maj 7 chord for stereo in & out
+ limiterTestUIP[i]->setParamValue(ndx, sineFreq);
+#endif
+ }
+ inited = true;
+ }
+ int getNumInputs() override { return(mNumChannels); }
+ int getNumOutputs() override { return(mNumChannels); }
+ void compute(int nframes, float** inputs, float** outputs) override;
+
+ void setWarningAmplitude(double wa) { // setting to 0 turns off warnings
+ warningAmp = std::max(0.0,std::min(1.0,wa));
+ }
+
+ private:
+
+ void checkAmplitudes(int nframes, float* buf) {
+ const int maxWarningInterval { 10000 }; // this could become an option
+ assert(warningAmp > 0.0);
+ assert(mNumClients > 0);
+ for (int i=0; i<nframes; i++) {
+ double tmp_sample = double(buf[i]);
+ double limiterAmp = fabs(tmp_sample)/sqrt(double(mNumClients)); // KEEP IN SYNC with gain in ../faust-src/limiterdsp.dsp
+ if (limiterAmp >= warningAmp) {
+ warnCount++;
+ peakMagnitude = std::max(peakMagnitude,limiterAmp);
+ if (warnCount==nextWarning) {
+ double peakMagnitudeDB = 20.0 * std::log10(peakMagnitude);
+ double warningAmpDB = 20.0 * std::log10(warningAmp);
+ if (warnCount==1) {
+ if (warningAmp == 1.0) {
+ std::cerr << "*** Limiter.cpp: Audio HARD-CLIPPED!\n";
+ fprintf(stderr, "\tReduce your audio input level(s) by %0.1f dB to avoid this.\n", peakMagnitudeDB);
+ } else {
+ fprintf(stderr,
+ "*** Limiter.cpp: Amplitude levels must stay below %0.1f dBFS to avoid compression.\n",
+ warningAmpDB);
+ fprintf(stderr, "\tReduce input level(s) by %0.1f dB to achieve this.\n",
+ peakMagnitudeDB-warningAmpDB);
+ }
+ } else {
+ fprintf(stderr, "\tReduce audio input level(s) by %0.1f dB to avoid limiter compression distortion.\n",
+ peakMagnitudeDB-warningAmpDB);
+ }
+ peakMagnitude = 0.0; // reset for next group measurement
+ if (nextWarning < maxWarningInterval) { // don't let it stop reporting for too long
+ nextWarning *= 10;
+ } else {
+ warnCount=0;
+ }
+ } // warnCount==nextWarning
+ } // above warningAmp
+ } // loop over frames
+ } // checkAmplitudes()
+
+private:
+ float fs;
+ int mNumChannels;
+ int mNumClients;
+ std::vector<limiterdsp*> limiterP;
+ std::vector<APIUI*> limiterUIP;
+#ifdef SINE_TEST
+ std::vector<limitertest*> limiterTestP;
+ std::vector<APIUI*> limiterTestUIP;
+#endif
+ double warningAmp;
+ uint32_t warnCount;
+ double peakMagnitude;
+ uint32_t nextWarning;
+};
+
+#endif
diff --git a/src/PacketHeader.cpp b/src/PacketHeader.cpp
index 56ac606..5511f94 100644
--- a/src/PacketHeader.cpp
+++ b/src/PacketHeader.cpp
@@ -133,11 +133,11 @@ void DefaultHeader::checkPeerSettings(int8_t* full_packet)
// Check Buffer Size
if ( peer_header->BufferSize != mHeader.BufferSize )
{
- std::cerr << "ERROR: Peer Buffer Size is : " << peer_header->BufferSize << endl;
- std::cerr << " Local Buffer Size is : " << mHeader.BufferSize << endl;
- std::cerr << "Make sure both machines use same buffer size" << endl;
- std::cerr << gPrintSeparator << endl;
- error = true;
+ std::cerr << "WARNING: Peer Buffer Size is : " << peer_header->BufferSize << endl;
+ std::cerr << " Local Buffer Size is : " << mHeader.BufferSize << endl;
+ //std::cerr << "Make sure both machines use same buffer size" << endl;
+ //std::cerr << gPrintSeparator << endl;
+ //error = true;
}
// Check Sampling Rate
diff --git a/src/PacketHeader.h b/src/PacketHeader.h
index 094d424..80f38b8 100644
--- a/src/PacketHeader.h
+++ b/src/PacketHeader.h
@@ -165,7 +165,7 @@ public:
signals:
- void signalError(const char* error_message);
+ void signalError(const QString &error_message);
private:
diff --git a/src/ProcessPlugin.h b/src/ProcessPlugin.h
index e0b23f3..fb48cca 100644
--- a/src/ProcessPlugin.h
+++ b/src/ProcessPlugin.h
@@ -65,17 +65,33 @@ public:
//virtual void buildUserInterface(UI* interface) = 0;
+ virtual char* getName() {
+ char* pluginName { const_cast<char*>(typeid(*this).name()) }; // get name of DERIVED class
+ while (isdigit(*pluginName)) { pluginName++; }
+ return pluginName;
+ }
+
/** \brief Do proper Initialization of members and class instances. By default this
* initializes the Sampling Frequency. If a class instance depends on the
* sampling frequency, it should be initialize here.
*/
- virtual void init(int samplingRate) { fSamplingFreq = samplingRate; };
+ virtual void init(int samplingRate) {
+ fSamplingFreq = samplingRate;
+ if (verbose) {
+ char* derivedClassName = getName();
+ printf("%s: init(%d)\n",derivedClassName,samplingRate);
+ }
+ }
+ virtual bool getInited() { return inited; }
+ virtual void setVerbose(bool v) { verbose = v; }
/// \brief Compute process
virtual void compute(int nframes, float** inputs, float** outputs) = 0;
protected:
int fSamplingFreq; ///< Faust Data member, Sampling Rate
+ bool inited = false;
+ bool verbose = false;
};
#endif
diff --git a/src/Reverb.cpp b/src/Reverb.cpp
new file mode 100644
index 0000000..abc2c5f
--- /dev/null
+++ b/src/Reverb.cpp
@@ -0,0 +1,70 @@
+//*****************************************************************
+/*
+ JackTrip: A System for High-Quality Audio Network Performance
+ over the Internet
+
+ Copyright (c) 2020 Julius Smith, Juan-Pablo Caceres, Chris Chafe.
+ SoundWIRE group at CCRMA, Stanford University.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+*/
+//*****************************************************************
+
+/**
+ * \file Reverb.cpp
+ * \author Julius Smith, based on Limiter.h
+ * \date August 2020
+ */
+
+
+#include "Reverb.h"
+#include "jacktrip_types.h"
+
+#include <iostream>
+
+//*******************************************************************************
+void Reverb::compute(int nframes, float** inputs, float** outputs)
+{
+ if (not inited) {
+ std::cerr << "*** Reverb " << this << ": init never called! Doing it now.\n";
+ if (fSamplingFreq <= 0) {
+ fSamplingFreq = 48000;
+ std::cout << "Reverb " << this << ": *** HAD TO GUESS the sampling rate (chose 48000 Hz) ***\n";
+ }
+ init(fSamplingFreq);
+ }
+ if (mReverbLevel <= 1.0) {
+ if (mNumInChannels == 1) {
+ freeverbMonoP->compute(nframes, inputs, outputs);
+ } else {
+ assert(mNumInChannels == 2);
+ freeverbStereoP->compute(nframes, inputs, outputs);
+ }
+ } else {
+ if (mNumInChannels == 1) {
+ zitarevMonoP->compute(nframes, inputs, outputs);
+ } else {
+ assert(mNumInChannels == 2);
+ zitarevStereoP->compute(nframes, inputs, outputs);
+ }
+ }
+}
diff --git a/src/Reverb.h b/src/Reverb.h
new file mode 100644
index 0000000..3a7fd84
--- /dev/null
+++ b/src/Reverb.h
@@ -0,0 +1,158 @@
+//*****************************************************************
+/*
+ JackTrip: A System for High-Quality Audio Network Performance
+ over the Internet
+
+ Copyright (c) 2020 Julius Smith, Juan-Pablo Caceres, Chris Chafe.
+ SoundWIRE group at CCRMA, Stanford University.
+
+ Permission is hereby granted, free of charge, to any person
+ obtaining a copy of this software and associated documentation
+ files (the "Software"), to deal in the Software without
+ restriction, including without limitation the rights to use,
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the
+ Software is furnished to do so, subject to the following
+ conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ OTHER DEALINGS IN THE SOFTWARE.
+*/
+//*****************************************************************
+
+/**
+ * \file Reverb.h
+ * \author Julius Smith, based on Limiter.h
+ * \date August 2020
+ */
+
+
+/** \brief Applies freeverb or zitarev from the faustlibraries distribution: reverbs.lib
+ *
+ */
+#ifndef __REVERB_H__
+#define __REVERB_H__
+
+//#define SINE_TEST
+
+#include "ProcessPlugin.h"
+#include "freeverbdsp.h" // stereo in and out
+#include "freeverbmonodsp.h" // mono in and out (there is no mono to stereo case in jacktrip as yet)
+#include "zitarevdsp.h" // stereo in and out
+#include "zitarevmonodsp.h" // mono in and out
+
+/** \brief A Reverb is an echo-based delay effect,
+ * providing a virtual acoustic listening space.
+ */
+class Reverb : public ProcessPlugin
+{
+public:
+ /// \brief The class constructor sets the number of channels to limit
+ Reverb(int numInChans, int numOutChans, float reverbLevel = 1.0, bool verboseFlag = false) // xtor
+ : mNumInChannels(numInChans), mNumOutChannels(numOutChans), mReverbLevel(reverbLevel)
+ {
+ setVerbose(verboseFlag);
+ if ( mNumInChannels < 1 ) {
+ std::cerr << "*** Reverb.h: must have at least one input audio channels\n";
+ mNumInChannels = 1;
+ }
+ if ( mNumInChannels > 2 ) {
+ std::cerr << "*** Reverb.h: limiting number of audio output channels to 2\n";
+ mNumInChannels = 2;
+ }
+#if 0
+ std::cout << "Reverb: constructed for "
+ << mNumInChannels << " input channels and "
+ << mNumOutChannels << " output channels with reverb level = "
+ << mReverbLevel << "\n";
+#endif
+
+ if (mReverbLevel <= 1.0) { // freeverb:
+ freeverbStereoP = new freeverbdsp; // stereo input and output
+ freeverbMonoP = new freeverbmonodsp; // mono input, stereo output
+ freeverbStereoUIP = new APIUI; // #included in *dsp.h
+ freeverbMonoUIP = new APIUI;
+ freeverbStereoP->buildUserInterface(freeverbStereoUIP);
+ freeverbMonoP->buildUserInterface(freeverbMonoUIP);
+ // std::cout << "Using freeverb\n";
+ } else {
+ zitarevStereoP = new zitarevdsp; // stereo input and output
+ zitarevMonoP = new zitarevmonodsp; // mono input, stereo output
+ zitarevStereoUIP = new APIUI;
+ zitarevMonoUIP = new APIUI;
+ zitarevStereoP->buildUserInterface(zitarevStereoUIP);
+ zitarevMonoP->buildUserInterface(zitarevMonoUIP);
+ // std::cout << "Using zitarev\n";
+ }
+ }
+
+ /// \brief The class destructor
+ virtual ~Reverb() {
+ if (mReverbLevel <= 1.0) { // freeverb:
+ delete freeverbStereoP;
+ delete freeverbMonoP;
+ delete freeverbStereoUIP;
+ delete freeverbMonoUIP;
+ } else {
+ delete zitarevStereoP;
+ delete zitarevMonoP;
+ delete zitarevStereoUIP;
+ delete zitarevMonoUIP;
+ }
+ }
+
+ void init(int samplingRate) override {
+ ProcessPlugin::init(samplingRate);
+ // std::cout << "Reverb: init(" << samplingRate << ")\n";
+ if (samplingRate != fSamplingFreq) {
+ std::cerr << "Sampling rate not set by superclass!\n";
+ std::exit(1); }
+ fs = float(fSamplingFreq);
+ if (mReverbLevel <= 1.0) { // freeverb:
+ freeverbStereoP->init(fs); // compression filter parameters depend on sampling rate
+ freeverbMonoP->init(fs); // compression filter parameters depend on sampling rate
+ int ndx = freeverbStereoUIP->getParamIndex("Wet");
+ freeverbStereoUIP->setParamValue(ndx, mReverbLevel);
+ freeverbMonoUIP->setParamValue(ndx, mReverbLevel);
+ } else { // zitarev:
+ zitarevStereoP->init(fs); // compression filter parameters depend on sampling rate
+ zitarevMonoP->init(fs); // compression filter parameters depend on sampling rate
+ int ndx = zitarevStereoUIP->getParamIndex("Wet");
+ float zitaLevel = mReverbLevel-1.0f; // range within zitarev is 0 to 1 (our version only)
+ zitarevStereoUIP->setParamValue(ndx, zitaLevel);
+ zitarevMonoUIP->setParamValue(ndx, zitaLevel);
+ }
+ inited = true;
+ }
+ int getNumInputs() override { return(mNumInChannels); }
+ int getNumOutputs() override { return(mNumOutChannels); }
+ void compute(int nframes, float** inputs, float** outputs) override;
+
+private:
+ float fs;
+ int mNumInChannels;
+ int mNumOutChannels;
+
+ float mReverbLevel;
+
+ freeverbdsp* freeverbStereoP;
+ freeverbmonodsp* freeverbMonoP;
+ APIUI* freeverbStereoUIP;
+ APIUI* freeverbMonoUIP;
+
+ zitarevdsp* zitarevStereoP;
+ zitarevmonodsp* zitarevMonoP;
+ APIUI* zitarevStereoUIP;
+ APIUI* zitarevMonoUIP;
+};
+
+#endif
diff --git a/src/RingBuffer.cpp b/src/RingBuffer.cpp
index 124399e..e9ff28c 100644
--- a/src/RingBuffer.cpp
+++ b/src/RingBuffer.cpp
@@ -42,6 +42,8 @@
#include <cstring>
#include <cstdlib>
#include <stdexcept>
+#include <cmath>
+#include "JackTrip.h"
using std::cout; using std::endl;
@@ -54,40 +56,55 @@ RingBuffer::RingBuffer(int SlotSize, int NumSlots) :
mReadPosition(0),
mWritePosition(0),
mFullSlots(0),
- mRingBuffer(new int8_t[mTotalSize]),
- mLastReadSlot(new int8_t[mSlotSize])
+ mRingBuffer(NULL),
+ mLastReadSlot(NULL)
{
- //QMutexLocker locker(&mMutex); // lock the mutex
-
- // Verify if there's enough space to for the buffers
- if ( (mRingBuffer == NULL) || (mLastReadSlot == NULL) ) {
- //std::cerr << "ERROR: RingBuffer out of memory!" << endl;
- //std::cerr << "Exiting program..." << endl;
- //std::exit(1);
- throw std::length_error("RingBuffer out of memory!");
+ if (0 < mTotalSize) {
+ mRingBuffer = new int8_t[mTotalSize];
+ mLastReadSlot = new int8_t[mSlotSize];
+ //QMutexLocker locker(&mMutex); // lock the mutex
+
+ // Verify if there's enough space to for the buffers
+ if ( (mRingBuffer == NULL) || (mLastReadSlot == NULL) ) {
+ //std::cerr << "ERROR: RingBuffer out of memory!" << endl;
+ //std::cerr << "Exiting program..." << endl;
+ //std::exit(1);
+ throw std::length_error("RingBuffer out of memory!");
+ }
+
+ // Set the buffers to zeros
+ /*
+ for (int i=0; i<mTotalSize; i++) {
+ mRingBuffer[i] = 0; // Initialize all elements to zero.
+ }
+ */
+ std::memset(mRingBuffer, 0, mTotalSize); // set buffer to 0
+ /*
+ for (int i=0; i<mSlotSize; i++) {
+ mLastReadSlot[i] = 0; // Initialize all elements to zero.
+ }
+ */
+ std::memset(mLastReadSlot, 0, mSlotSize); // set buffer to 0
+ mWritePosition = ( (NumSlots/2) * SlotSize ) % mTotalSize;
}
- // Set the buffers to zeros
- /*
- for (int i=0; i<mTotalSize; i++) {
- mRingBuffer[i] = 0; // Initialize all elements to zero.
- }
- */
- std::memset(mRingBuffer, 0, mTotalSize); // set buffer to 0
- /*
- for (int i=0; i<mSlotSize; i++) {
- mLastReadSlot[i] = 0; // Initialize all elements to zero.
- }
- */
- std::memset(mLastReadSlot, 0, mSlotSize); // set buffer to 0
-
-
// Advance write position to half of the RingBuffer
- mWritePosition = ( (NumSlots/2) * SlotSize ) % mTotalSize;
// Udpate Full Slots accordingly
mFullSlots = (NumSlots/2);
+ mLevelDownRate = 0.01;
+ mStatUnit = 1;
mUnderruns = 0;
mOverflows = 0;
+ mSkew0 = 0;
+ mSkewRaw = 0;
+ mLevelCur = mFullSlots;
+ mLevel = mLevelCur;
+ mBufDecOverflow = 0;
+ mBufDecPktLoss = 0;
+ mBufIncUnderrun = 0;
+ mBufIncCompensate = 0;
+ mBroadcastSkew = 0;
+ mBroadcastDelta = 0;
}
@@ -105,6 +122,7 @@ RingBuffer::~RingBuffer()
void RingBuffer::insertSlotBlocking(const int8_t* ptrToSlot)
{
QMutexLocker locker(&mMutex); // lock the mutex
+ updateReadStats();
// Check if there is space available to write a slot
// If the Ringbuffer is full, it waits for the bufferIsNotFull condition
@@ -127,12 +145,16 @@ void RingBuffer::insertSlotBlocking(const int8_t* ptrToSlot)
void RingBuffer::readSlotBlocking(int8_t* ptrToReadSlot)
{
QMutexLocker locker(&mMutex); // lock the mutex
+ ++mReadsNew;
// Check if there are slots available to read
// If the Ringbuffer is empty, it waits for the bufferIsNotEmpty condition
while (mFullSlots == 0) {
//std::cerr << "READ UNDER-RUN BLOCKING before" << endl;
- mBufferIsNotEmpty.wait(&mMutex);
+ mBufferIsNotEmpty.wait(&mMutex, 200);
+ if (JackTrip::sJackStopped) {
+ return;
+ }
}
// Copy mSlotSize bytes to ReadSlot
@@ -148,9 +170,20 @@ void RingBuffer::readSlotBlocking(int8_t* ptrToReadSlot)
//*******************************************************************************
-void RingBuffer::insertSlotNonBlocking(const int8_t* ptrToSlot)
+bool RingBuffer::insertSlotNonBlocking(const int8_t* ptrToSlot, int len, int lostLen)
{
+ if (len != mSlotSize && 0 != len) {
+ // RingBuffer does not suppport mixed buf sizes
+ return false;
+ }
QMutexLocker locker(&mMutex); // lock the mutex
+ if (0 < lostLen) {
+ int lostCount = lostLen / mSlotSize;
+ mBufDecPktLoss += lostCount;
+ mSkewRaw -= lostCount;
+ mLevelCur -= lostCount;
+ }
+ updateReadStats();
// Check if there is space available to write a slot
// If the Ringbuffer is full, it returns without writing anything
@@ -160,7 +193,7 @@ void RingBuffer::insertSlotNonBlocking(const int8_t* ptrToSlot)
if (mFullSlots == mNumSlots) {
//std::cout << "OUPUT OVERFLOW NON BLOCKING = " << mNumSlots << std::endl;
overflowReset();
- return;
+ return true;
}
// Copy mSlotSize bytes to mRingBuffer
@@ -170,6 +203,7 @@ void RingBuffer::insertSlotNonBlocking(const int8_t* ptrToSlot)
mFullSlots++; //update full slots
// Wake threads waitng for bufferIsNotFull condition
mBufferIsNotEmpty.wakeAll();
+ return true;
}
@@ -177,11 +211,17 @@ void RingBuffer::insertSlotNonBlocking(const int8_t* ptrToSlot)
void RingBuffer::readSlotNonBlocking(int8_t* ptrToReadSlot)
{
QMutexLocker locker(&mMutex); // lock the mutex
-
+ ++mReadsNew;
+ if (mFullSlots < mLevelCur) {
+ mLevelCur = std::max((double)mFullSlots, mLevelCur-mLevelDownRate);
+ }
+ else {
+ mLevelCur = mFullSlots;
+ }
// Check if there are slots available to read
// If the Ringbuffer is empty, it returns a buffer of zeros and rests the buffer
- if (mFullSlots == 0) {
+ if (mFullSlots <= 0) {
// Returns a buffer of zeros if there's nothing to read
//std::cerr << "READ UNDER-RUN NON BLOCKING = " << mNumSlots << endl;
//std::memset(ptrToReadSlot, 0, mSlotSize);
@@ -203,6 +243,14 @@ void RingBuffer::readSlotNonBlocking(int8_t* ptrToReadSlot)
//*******************************************************************************
+// Not supported in RingBuffer
+void RingBuffer::readBroadcastSlot(int8_t* ptrToReadSlot)
+{
+ std::memset(ptrToReadSlot, 0, mSlotSize);
+}
+
+
+//*******************************************************************************
void RingBuffer::setUnderrunReadSlot(int8_t* ptrToReadSlot)
{
std::memset(ptrToReadSlot, 0, mSlotSize);
@@ -228,7 +276,7 @@ void RingBuffer::underrunReset()
//mFullSlots += mNumSlots/2;
// There's nothing new to read, so we clear the whole buffer (Set the entire buffer to 0)
std::memset(mRingBuffer, 0, mTotalSize);
- ++mUnderruns;
+ ++mUnderrunsNew;
}
@@ -238,9 +286,12 @@ void RingBuffer::overflowReset()
{
// Advance the read pointer 1/2 the ring buffer
//mReadPosition = ( mWritePosition + ( (mNumSlots/2) * mSlotSize ) ) % mTotalSize;
- mReadPosition = ( mReadPosition + ( (mNumSlots/2) * mSlotSize ) ) % mTotalSize;
- mFullSlots -= mNumSlots/2;
- mOverflows += mNumSlots/2 + 1;
+ int d = mNumSlots / 2;
+ mReadPosition = ( mReadPosition + ( d * mSlotSize ) ) % mTotalSize;
+ mFullSlots -= d;
+ mOverflows += d + 1;
+ mBufDecOverflow += d + 1;
+ mLevelCur -= d;
}
@@ -256,11 +307,45 @@ void RingBuffer::debugDump() const
//*******************************************************************************
bool RingBuffer::getStats(RingBuffer::IOStat* stat, bool reset)
{
+ QMutexLocker locker(&mMutex);
if (reset) {
mUnderruns = 0;
mOverflows = 0;
+ mSkew0 = mLevel;
+ mSkewRaw = 0;
+ mBufDecOverflow = 0;
+ mBufDecPktLoss = 0;
+ mBufIncUnderrun = 0;
+ mBufIncCompensate = 0;
+ mBroadcastSkew = 0;
}
- stat->underruns = mUnderruns;
- stat->overflows = mOverflows;
+ stat->underruns = mUnderruns / mStatUnit;
+ stat->overflows = mOverflows / mStatUnit;
+ stat->skew = (int32_t)((mSkew0 - mLevel + mBufIncUnderrun + mBufIncCompensate
+ - mBufDecOverflow - mBufDecPktLoss)) / mStatUnit;
+ stat->skew_raw = mSkewRaw / mStatUnit;
+ stat->level = mLevel / mStatUnit;
+
+ stat->buf_dec_overflows = mBufDecOverflow / mStatUnit;
+ stat->buf_dec_pktloss = mBufDecPktLoss / mStatUnit;
+ stat->buf_inc_underrun = mBufIncUnderrun / mStatUnit;
+ stat->buf_inc_compensate = mBufIncCompensate / mStatUnit;
+ stat->broadcast_skew = mBroadcastSkew;
+ stat->broadcast_delta = mBroadcastDelta;
+
+ stat->autoq_corr = 0;
+ stat->autoq_rate = 0;
return true;
}
+
+//*******************************************************************************
+void RingBuffer::updateReadStats()
+{
+ --mSkewRaw;
+ mSkewRaw += mReadsNew;
+ mReadsNew = 0;
+ mUnderruns += mUnderrunsNew;
+ mBufIncUnderrun += mUnderrunsNew;
+ mUnderrunsNew = 0;
+ mLevel = std::ceil(mLevelCur);
+}
diff --git a/src/RingBuffer.h b/src/RingBuffer.h
index 78e137f..e68d625 100644
--- a/src/RingBuffer.h
+++ b/src/RingBuffer.h
@@ -95,16 +95,29 @@ public:
/** \brief Same as insertSlotBlocking but non-blocking (asynchronous)
* \param ptrToSlot Pointer to slot to insert into the RingBuffer
*/
- void insertSlotNonBlocking(const int8_t* ptrToSlot);
+ virtual bool insertSlotNonBlocking(const int8_t* ptrToSlot, int len, int lostLen);
/** \brief Same as readSlotBlocking but non-blocking (asynchronous)
* \param ptrToReadSlot Pointer to read slot from the RingBuffer
*/
- void readSlotNonBlocking(int8_t* ptrToReadSlot);
+ virtual void readSlotNonBlocking(int8_t* ptrToReadSlot);
+ virtual void readBroadcastSlot(int8_t* ptrToReadSlot);
struct IOStat {
uint32_t underruns;
uint32_t overflows;
+ int32_t skew;
+ int32_t skew_raw;
+ int32_t level;
+ uint32_t buf_dec_overflows;
+ uint32_t buf_dec_pktloss;
+ uint32_t buf_inc_underrun;
+ uint32_t buf_inc_compensate;
+ int32_t broadcast_skew;
+ int32_t broadcast_delta;
+
+ int32_t autoq_corr;
+ int32_t autoq_rate;
};
virtual bool getStats(IOStat* stat, bool reset);
@@ -124,20 +137,19 @@ protected:
*/
virtual void setMemoryInReadSlotWithLastReadSlot(int8_t* ptrToReadSlot);
-private:
-
/// \brief Resets the ring buffer for reads under-runs non-blocking
void underrunReset();
/// \brief Resets the ring buffer for writes over-flows non-blocking
void overflowReset();
/// \brief Helper method to debug, prints member variables to terminal
void debugDump() const;
+ void updateReadStats();
- const int mSlotSize; ///< The size of one slot in byes
- const int mNumSlots; ///< Number of Slots
- const int mTotalSize; ///< Total size of the mRingBuffer = mSlotSize*mNumSlotss
- int mReadPosition; ///< Read Positions in the RingBuffer (Tail)
- int mWritePosition; ///< Write Position in the RingBuffer (Head)
+ /*const*/ int mSlotSize; ///< The size of one slot in byes
+ /*const*/ int mNumSlots; ///< Number of Slots
+ /*const*/ int mTotalSize; ///< Total size of the mRingBuffer = mSlotSize*mNumSlotss
+ uint32_t mReadPosition; ///< Read Positions in the RingBuffer (Tail)
+ uint32_t mWritePosition; ///< Write Position in the RingBuffer (Head)
int mFullSlots; ///< Number of used (full) slots, in slot-size
int8_t* mRingBuffer; ///< 8-bit array of data (1-byte)
int8_t* mLastReadSlot; ///< Last slot read
@@ -146,8 +158,29 @@ private:
QMutex mMutex; ///< Mutex to protect read and write operations
QWaitCondition mBufferIsNotFull; ///< Buffer not full condition to monitor threads
QWaitCondition mBufferIsNotEmpty; ///< Buffer not empty condition to monitor threads
- std::atomic<uint32_t> mUnderruns;
- std::atomic<uint32_t> mOverflows;
+
+ // IO stat
+ int mStatUnit;
+ uint32_t mUnderruns;
+ uint32_t mOverflows;
+ int32_t mSkewRaw;
+ double mLevelCur;
+ double mLevelDownRate;
+ int32_t mLevel;
+
+ uint32_t mBufDecOverflow;
+ uint32_t mBufDecPktLoss;
+ uint32_t mBufIncUnderrun;
+ uint32_t mBufIncCompensate;
+
+ // temp counters for reads
+ uint32_t mReadsNew;
+ uint32_t mUnderrunsNew;
+ int32_t mSkew0;
+
+ // broadcast counters
+ int32_t mBroadcastSkew;
+ int32_t mBroadcastDelta;
};
#endif
diff --git a/src/Settings.cpp b/src/Settings.cpp
index bbc386b..4d08021 100644
--- a/src/Settings.cpp
+++ b/src/Settings.cpp
@@ -37,40 +37,49 @@
#include "Settings.h"
#include "LoopBack.h"
-#include "NetKS.h"
+//#include "NetKS.h"
+#include "Effects.h"
#ifdef WAIR // wair
#include "ap8x2.dsp.h"
#include "Stk16.dsp.h"
#endif // endwhere
-#include "UdpHubListener.h"
-#include "JackTripWorker.h"
+//#include "JackTripWorker.h"
#include "jacktrip_globals.h"
#include <iostream>
#include <getopt.h> // for command line parsing
#include <cstdlib>
+#include <assert.h>
+#include <ctype.h>
-#include "ThreadPoolTest.h"
+//#include "ThreadPoolTest.h"
using std::cout; using std::endl;
int gVerboseFlag = 0;
+enum JTLongOptIDS {
+ OPT_BUFSTRATEGY = 1001,
+ OPT_SIMLOSS,
+ OPT_SIMJITTER,
+ OPT_BROADCAST,
+ OPT_RTUDPPRIORITY,
+};
//*******************************************************************************
Settings::Settings() :
- mJackTrip(NULL),
mJackTripMode(JackTrip::SERVER),
mDataProtocol(JackTrip::UDP),
mNumChans(2),
mBufferQueueLength(gDefaultQueueLength),
mAudioBitResolution(AudioInterface::BIT16),
mBindPortNum(gDefaultPort), mPeerPortNum(gDefaultPort),
- mServerUdpPortNum(NULL),
- mClientName(NULL),
- mUnderrrunZero(false),
+ mServerUdpPortNum(0),
+ mUnderrunMode(JackTrip::WAVETABLE),
+ mStopOnTimeout(false),
+ mBufferStrategy(1),
mLoopBack(false),
#ifdef WAIR // WAIR
mNumNetRevChans(0),
@@ -87,19 +96,23 @@ Settings::Settings() :
mChanfeDefaultBS(false),
mHubConnectionMode(JackTrip::SERVERTOCLIENT),
mConnectDefaultAudioPorts(true),
- mIOStatTimeout(0)
+ mIOStatTimeout(0),
+ mEffects(false), // outgoing limiter OFF by default
+ mSimulatedLossRate(0.0),
+ mSimulatedJitterRate(0.0),
+ mSimulatedDelayRel(0.0),
+ mBroadcastQueue(0),
+ mUseRtUdpPriority(false)
{}
//*******************************************************************************
-Settings::~Settings()
-{
- stopJackTrip();
- delete mJackTrip;
-}
+Settings::~Settings() = default;
//*******************************************************************************
void Settings::parseInput(int argc, char** argv)
{
+ // Always use decimal point for floating point numbers
+ setlocale( LC_NUMERIC, "C" );
// If no command arguments are given, print instructions
if(argc == 1) {
printUsage();
@@ -112,49 +125,60 @@ void Settings::parseInput(int argc, char** argv)
//----------------------------------------------------------------------------
static struct option longopts[] = {
// These options don't set a flag.
- { "numchannels", required_argument, NULL, 'n' }, // Number of input and output channels
+ { "numchannels", required_argument, NULL, 'n' }, // Number of input and output channels
#ifdef WAIR // WAIR
- { "wair", no_argument, NULL, 'w' }, // Run in LAIR mode, sets numnetrevchannels
- { "addcombfilterlength", required_argument, NULL, 'N' }, // added comb filter length
- { "combfilterfeedback", required_argument, NULL, 'H' }, // comb filter feedback
+ { "wair", no_argument, NULL, 'w' }, // Run in LAIR mode, sets numnetrevchannels
+ { "addcombfilterlength", required_argument, NULL, 'N' }, // added comb filter length
+ { "combfilterfeedback", required_argument, NULL, 'H' }, // comb filter feedback
#endif // endwhere
- { "server", no_argument, NULL, 's' }, // Run in server mode
- { "client", required_argument, NULL, 'c' }, // Run in client mode, set server IP address
- { "localaddress", required_argument, NULL, 'L' }, // set local address e.g., 127.0.0.2 for second instance on same host
- { "jacktripserver", no_argument, NULL, 'S' }, // Run in JamLink mode
- { "pingtoserver", required_argument, NULL, 'C' }, // Run in ping to server mode, set server IP address
- { "portoffset", required_argument, NULL, 'o' }, // Port Offset from 4464
- { "bindport", required_argument, NULL, 'B' }, // Port Offset from 4464
- { "peerport", required_argument, NULL, 'P' }, // Port Offset from 4464
- { "udpbaseport", required_argument, NULL, 'U' }, // Server udp base port (defaults to 61002)
- { "queue", required_argument, NULL, 'q' }, // Queue Length
- { "redundancy", required_argument, NULL, 'r' }, // Redundancy
- { "bitres", required_argument, NULL, 'b' }, // Audio Bit Resolution
- { "zerounderrun", no_argument, NULL, 'z' }, // Use Underrun to Zeros Mode
- { "loopback", no_argument, NULL, 'l' }, // Run in loopback mode
- { "jamlink", no_argument, NULL, 'j' }, // Run in JamLink mode
- { "emptyheader", no_argument, NULL, 'e' }, // Run in JamLink mode
- { "clientname", required_argument, NULL, 'J' }, // Run in JamLink mode
- { "rtaudio", no_argument, NULL, 'R' }, // Run in JamLink mode
- { "srate", required_argument, NULL, 'T' }, // Set Sample Rate
- { "deviceid", required_argument, NULL, 'd' }, // Set RTAudio device id to use
- { "bufsize", required_argument, NULL, 'F' }, // Set buffer Size
- { "nojackportsconnect" , no_argument, NULL, 'D'}, // Don't connect default Audio Ports
- { "version", no_argument, NULL, 'v' }, // Version Number
- { "verbose", no_argument, NULL, 'V' }, // Verbose mode
- { "hubpatch", required_argument, NULL, 'p' }, // Set hubConnectionMode for auto patch in Jack
- { "iostat", required_argument, NULL, 'I' }, // Set IO stat timeout
- { "iostatlog", required_argument, NULL, 'G' }, // Set IO stat log file
- { "help", no_argument, NULL, 'h' }, // Print Help
- { NULL, 0, NULL, 0 }
-};
+ { "server", no_argument, NULL, 's' }, // Run in P2P server mode
+ { "client", required_argument, NULL, 'c' }, // Run in P2P client mode, set server IP address
+ { "localaddress", required_argument, NULL, 'L' }, // set local address e.g., 127.0.0.2 for second instance on same host
+ { "jacktripserver", no_argument, NULL, 'S' }, // Run in JamLink mode
+ { "pingtoserver", required_argument, NULL, 'C' }, // Run in ping to server mode, set server IP address
+ { "portoffset", required_argument, NULL, 'o' }, // Port Offset from 4464
+ { "bindport", required_argument, NULL, 'B' }, // Port Offset from 4464
+ { "peerport", required_argument, NULL, 'P' }, // Port Offset from 4464
+ { "udpbaseport", required_argument, NULL, 'U' }, // Server udp base port (defaults to 61002)
+ { "queue", required_argument, NULL, 'q' }, // Queue Length
+ { "redundancy", required_argument, NULL, 'r' }, // Redundancy
+ { "bitres", required_argument, NULL, 'b' }, // Audio Bit Resolution
+ { "zerounderrun", no_argument, NULL, 'z' }, // Use Underrun to Zeros Mode
+ { "timeout", no_argument, NULL, 't' }, // Quit after 10 second network timeout
+ { "loopback", no_argument, NULL, 'l' }, // Run in loopback mode
+ { "jamlink", no_argument, NULL, 'j' }, // Run in JamLink mode
+ { "emptyheader", no_argument, NULL, 'e' }, // Run in JamLink mode
+ { "clientname", required_argument, NULL, 'J' }, // Run in JamLink mode
+ { "remotename", required_argument, NULL, 'K' }, // Client name on hub server
+ { "rtaudio", no_argument, NULL, 'R' }, // Run in JamLink mode
+ { "srate", required_argument, NULL, 'T' }, // Set Sample Rate
+ { "deviceid", required_argument, NULL, 'd' }, // Set RTAudio device id to use
+ { "bufsize", required_argument, NULL, 'F' }, // Set buffer Size
+ { "nojackportsconnect" , no_argument, NULL, 'D'}, // Don't connect default Audio Ports
+ { "version", no_argument, NULL, 'v' }, // Version Number
+ { "verbose", no_argument, NULL, 'V' }, // Verbose mode
+ { "hubpatch", required_argument, NULL, 'p' }, // Set hubConnectionMode for auto patch in Jack
+ { "iostat", required_argument, NULL, 'I' }, // Set IO stat timeout
+ { "iostatlog", required_argument, NULL, 'G' }, // Set IO stat log file
+ { "effects", required_argument, NULL, 'f' }, // Turn on outgoing compressor and incoming reverb, reverbLevel arg
+ { "overflowlimiting", required_argument, NULL, 'O' }, // Turn On limiter, cases 'i', 'o', 'io'
+ { "assumednumclients", required_argument, NULL, 'a' }, // assumed number of clients (sound sources) (otherwise 2)
+ { "bufstrategy", required_argument, NULL, OPT_BUFSTRATEGY }, // Set bufstrategy
+ { "simloss", required_argument, NULL, OPT_SIMLOSS },
+ { "simjitter", required_argument, NULL, OPT_SIMJITTER },
+ { "broadcast", required_argument, NULL, OPT_BROADCAST },
+ { "udprt", no_argument, NULL, OPT_RTUDPPRIORITY },
+ { "help", no_argument, NULL, 'h' }, // Print Help
+ { "examine-audio-delay", required_argument, NULL, 'x' }, // test mode - measure audio round-trip latency statistics
+ { NULL, 0, NULL, 0 }
+ };
// Parse Command Line Arguments
//----------------------------------------------------------------------------
/// \todo Specify mandatory arguments
int ch;
- while ( (ch = getopt_long(argc, argv,
- "n:N:H:sc:SC:o:B:P:U:q:r:b:zlwjeJ:RTd:F:p:DvVh", longopts, NULL)) != -1 )
+ while ((ch = getopt_long(argc, argv,
+ "n:N:H:sc:SC:o:B:P:U:q:r:b:ztlwjeJ:K:RTd:F:p:DvVhI:G:f:O:a:x:", longopts, NULL)) != -1)
switch (ch) {
case 'n': // Number of input and output channels
@@ -179,15 +203,15 @@ void Settings::parseInput(int argc, char** argv)
mClientRoomSize = atof(optarg); // cmd line comb feedback adjustment
break;
#endif // endwhere
- case 's': // Run in server mode
+ case 's': // Run in P2P server mode
//-------------------------------------------------------
mJackTripMode = JackTrip::SERVER;
break;
- case 'S': // Run in jacktripserver mode
+ case 'S': // Run in Hub server mode
//-------------------------------------------------------
mJackTripServer = true;
break;
- case 'c': // Client mode
+ case 'c': // P2P client mode
//-------------------------------------------------------
mJackTripMode = JackTrip::CLIENT;
mPeerAddress = optarg;
@@ -220,25 +244,32 @@ void Settings::parseInput(int argc, char** argv)
break;
case 'b':
//-------------------------------------------------------
- if ( atoi(optarg) == 8 ) {
- mAudioBitResolution = AudioInterface::BIT8; }
- else if ( atoi(optarg) == 16 ) {
- mAudioBitResolution = AudioInterface::BIT16; }
- else if ( atoi(optarg) == 24 ) {
- mAudioBitResolution = AudioInterface::BIT24; }
- else if ( atoi(optarg) == 32 ) {
- mAudioBitResolution = AudioInterface::BIT32; }
- else {
- std::cerr << "--bitres ERROR: Wrong bit resolution: "
- << atoi(optarg) << " is not supported." << endl;
+ if (atoi(optarg) == 8) {
+ mAudioBitResolution = AudioInterface::BIT8;
+ } else if (atoi(optarg) == 16) {
+ mAudioBitResolution = AudioInterface::BIT16;
+ } else if (atoi(optarg) == 24) {
+ mAudioBitResolution = AudioInterface::BIT24;
+ } else if (atoi(optarg) == 32) {
+ mAudioBitResolution = AudioInterface::BIT32;
+ } else {
printUsage();
- std::exit(1); }
+ std::cerr << "--bitres ERROR: Bit resolution: "
+ << atoi(optarg) << " is not supported." << endl;
+ std::exit(1);
+ }
break;
case 'q':
//-------------------------------------------------------
- if ( atoi(optarg) <= 0 ) {
- std::cerr << "--queue ERROR: The queue has to be equal or greater than 2" << endl;
+ if (0 == strncmp(optarg, "auto", 4)) {
+ mBufferQueueLength = -atoi(optarg+4);
+ if (0 == mBufferQueueLength) {
+ mBufferQueueLength = -500;
+ }
+ }
+ else if ( atoi(optarg) <= 0 ) {
printUsage();
+ std::cerr << "--queue ERROR: The queue has to be equal or greater than 2" << endl;
std::exit(1); }
else {
mBufferQueueLength = atoi(optarg);
@@ -247,8 +278,8 @@ void Settings::parseInput(int argc, char** argv)
case 'r':
//-------------------------------------------------------
if ( atoi(optarg) <= 0 ) {
- std::cerr << "--redundancy ERROR: The reduncancy has to be a positive integer" << endl;
printUsage();
+ std::cerr << "--redundancy ERROR: The redundancy has to be a positive integer" << endl;
std::exit(1); }
else {
mRedundancy = atoi(optarg);
@@ -256,7 +287,10 @@ void Settings::parseInput(int argc, char** argv)
break;
case 'z': // underrun to zero
//-------------------------------------------------------
- mUnderrrunZero = true;
+ mUnderrunMode = JackTrip::ZEROS;
+ break;
+ case 't': // quit on timeout
+ mStopOnTimeout = true;
break;
case 'l': // loopback
//-------------------------------------------------------
@@ -274,6 +308,10 @@ void Settings::parseInput(int argc, char** argv)
//-------------------------------------------------------
mClientName = optarg;
break;
+ case 'K': // Set Remote client Name
+ //-------------------------------------------------------
+ mRemoteClientName = optarg;
+ break;
case 'R': // RtAudio
//-------------------------------------------------------
mUseJack = false;
@@ -309,70 +347,204 @@ void Settings::parseInput(int argc, char** argv)
//-------------------------------------------------------
gVerboseFlag = true;
if (gVerboseFlag) std::cout << "Verbose mode" << std::endl;
+ mEffects.setVerboseFlag(gVerboseFlag);
break;
case 'p':
//-------------------------------------------------------
- if ( atoi(optarg) == 0 ) {
- mHubConnectionMode = JackTrip::SERVERTOCLIENT; }
- else if ( atoi(optarg) == 1 ) {
- mHubConnectionMode = JackTrip::CLIENTECHO; }
- else if ( atoi(optarg) == 2 ) {
- mHubConnectionMode = JackTrip::CLIENTFOFI; }
- else if ( atoi(optarg) == 3 ) {
- mHubConnectionMode = JackTrip::RESERVEDMATRIX; }
- else if ( atoi(optarg) == 4 ) {
- mHubConnectionMode = JackTrip::FULLMIX; }
- else {
+ if ( atoi(optarg) == 0 ) {
+ mHubConnectionMode = JackTrip::SERVERTOCLIENT;
+ } else if ( atoi(optarg) == 1 ) {
+ mHubConnectionMode = JackTrip::CLIENTECHO;
+ } else if ( atoi(optarg) == 2 ) {
+ mHubConnectionMode = JackTrip::CLIENTFOFI;
+ } else if ( atoi(optarg) == 3 ) {
+ mHubConnectionMode = JackTrip::RESERVEDMATRIX;
+ } else if ( atoi(optarg) == 4 ) {
+ mHubConnectionMode = JackTrip::FULLMIX;
+ } else if ( atoi(optarg) == 5 ) {
+ mHubConnectionMode = JackTrip::NOAUTO;
+ } else {
+ printUsage();
std::cerr << "-p ERROR: Wrong HubConnectionMode: "
<< atoi(optarg) << " is not supported." << endl;
- printUsage();
- std::exit(1); }
+ std::exit(1);
+ }
break;
case 'I': // IO Stat timeout
//-------------------------------------------------------
mIOStatTimeout = atoi(optarg);
if (0 > mIOStatTimeout) {
- std::cerr << "--iostat ERROR: negative timeout." << endl;
printUsage();
+ std::cerr << "--iostat ERROR: negative timeout." << endl;
std::exit(1);
}
break;
case 'G': // IO Stat log file
//-------------------------------------------------------
- mIOStatStream.open(optarg);
- if (!mIOStatStream.is_open()) {
+ mIOStatStream.reset(new std::ofstream(optarg));
+ if (!mIOStatStream->is_open()) {
+ printUsage();
std::cerr << "--iostatlog FAILED to open " << optarg
<< " for writing." << endl;
+ std::exit(1);
+ }
+ break;
+ case OPT_BUFSTRATEGY: // Buf strategy
+ mBufferStrategy = atoi(optarg);
+ if (-1 > mBufferStrategy || 2 < mBufferStrategy) {
+ std::cerr << "Unsupported buffer strategy " << optarg << endl;
printUsage();
std::exit(1);
}
break;
+ case OPT_SIMLOSS: // Simulate packet loss
+ mSimulatedLossRate = atof(optarg);
+ break;
+ case OPT_SIMJITTER: // Simulate jitter
+ char* endp;
+ mSimulatedJitterRate = strtod(optarg, &endp);
+ if (0 == *endp) {
+ mSimulatedDelayRel = 1.0;
+ }
+ else {
+ mSimulatedDelayRel = atof(endp+1);
+ }
+ break;
+ case OPT_BROADCAST: // Broadcast output
+ mBroadcastQueue = atoi(optarg);
+ break;
+ case OPT_RTUDPPRIORITY: // Use RT priority for UDPDataProtocol thread
+ mUseRtUdpPriority = true;
+ break;
case 'h':
//-------------------------------------------------------
printUsage();
std::exit(0);
break;
- default:
+ case 'O': { // Overflow limiter (i, o, or io)
+ //-------------------------------------------------------
+ char cmd[] { "--overflowlimiting (-O)" };
+ if (gVerboseFlag) {
+ printf("%s argument = %s\n",cmd,optarg);
+ }
+ int returnCode = mEffects.parseLimiterOptArg(cmd,optarg);
+ if (returnCode > 1) {
+ mEffects.printHelp(cmd,ch);
+ std::cerr << cmd << " required argument `" << optarg << "' is malformed\n";
+ std::exit(1);
+ } else if (returnCode == 1) {
+ std::exit(0); // benign but not continuing such as "help"
+ }
+ break; }
+ case 'a': { // assumed number of clients (applies to outgoing limiter)
+ //-------------------------------------------------------
+ char cmd[] { "--assumednumclients (-a)" };
+ if (gVerboseFlag) {
+ printf("%s argument = %s\n",cmd,optarg);
+ }
+ int returnCode = mEffects.parseAssumedNumClientsOptArg(cmd,optarg);
+ if (returnCode > 1) {
+ mEffects.printHelp(cmd,ch);
+ std::cerr << cmd << " required argument `" << optarg << "' is malformed\n";
+ std::exit(1);
+ } else if (returnCode == 1) {
+ std::exit(0); // help printed
+ }
+ break; }
+ case 'f': { // --effects (-f) effectsSpecArg
+ //-------------------------------------------------------
+ char cmd[] { "--effects (-f)" };
+ int returnCode = mEffects.parseEffectsOptArg(cmd,optarg);
+ if (returnCode > 1) {
+ mEffects.printHelp(cmd,ch);
+ std::cerr << cmd << " required argument `" << optarg << "' is malformed\n";
+ std::exit(1);
+ } else if (returnCode == 1) {
+ std::exit(0); // something benign but non-continuing like "help"
+ }
+ break; }
+ case 'x': { // examine connection (test mode)
+ //-------------------------------------------------------
+ char cmd[] { "--examine-audio-delay (-x)" };
+ if (tolower(optarg[0])=='h') {
+ mAudioTester.printHelp(cmd,ch);
+ std::exit(0);
+ }
+ mAudioTester.setEnabled(true);
+ if (optarg == 0 || optarg[0] == '-' || optarg[0] == 0) { // happens when no -f argument specified
+ printUsage();
+ std::cerr << cmd << " ERROR: Print-interval argument REQUIRED (set to 0.0 to see every delay)\n";
+ std::exit(1);
+ }
+ mAudioTester.setPrintIntervalSec(atof(optarg));
+ break; }
+ case ':': {
+ printUsage();
+ printf("*** Missing option argument *** see above for usage\n\n");
+ break; }
+ case '?': {
+ printUsage();
+ printf("*** Unknown, missing, or ambiguous option argument *** see above for usage\n\n");
+ std::exit(1);
+ break; }
+ default: {
//-------------------------------------------------------
printUsage();
- std::exit(0);
- break;
+ printf("*** Unrecognized option -%c *** see above for usage\n",ch);
+ std::exit(1);
+ break; }
}
// Warn user if undefined options where entered
//----------------------------------------------------------------------------
if (optind < argc) {
+ if (strcmp(argv[optind],"help")!=0) {
cout << gPrintSeparator << endl;
- cout << "WARINING: The following entered options have no effect." << endl;
- cout << " They will be ignored!" << endl;
- cout << " Type 'jacktrip' to see options." << endl;
+ cout << "*** Unexpected command-line argument(s): ";
for( ; optind < argc; optind++) {
- cout << "argument: " << argv[optind] << endl;
+ cout << argv[optind] << " ";
}
- cout << gPrintSeparator << endl;
+ cout << endl << gPrintSeparator << endl;
+ }
+ printUsage();
+ std::exit(1);
}
-}
+ assert(mNumChans>0);
+ mAudioTester.setSendChannel(mNumChans-1); // use last channel for latency testing
+ // Originally, testing only in the last channel was adopted
+ // because channel 0 ("left") was a clap track on CCRMA loopback
+ // servers. Now, however, we also do it in order to easily keep
+ // effects in all but the last channel, enabling silent testing
+ // in the last channel in parallel with normal operation of the others.
+
+ // Exit if options are incompatible
+ //----------------------------------------------------------------------------
+ bool haveSomeServerMode = not ((mJackTripMode == JackTrip::CLIENT) || (mJackTripMode == JackTrip::CLIENTTOPINGSERVER));
+ if (mEffects.getHaveEffect() && haveSomeServerMode) {
+ std::cerr << "*** --effects (-f) ERROR: Effects not yet supported server modes (-S and -s).\n\n";
+ std::exit(1);
+ }
+ if (mEffects.getHaveLimiter() && haveSomeServerMode) {
+ if (mEffects.getLimit() != Effects::LIMITER_MODE::LIMITER_OUTGOING) { // default case
+ std::cerr << "*** --overflowlimiting (-O) ERROR: Limiters not yet supported server modes (-S and -s).\n\n";
+ }
+ mEffects.setNoLimiters();
+ // don't exit since an outgoing limiter should be the default (could exit for incoming case):
+ // std::exit(1);
+ }
+ if (mAudioTester.getEnabled() && haveSomeServerMode) {
+ std::cerr << "*** --examine-audio-delay (-x) ERROR: Audio latency measurement not supported in server modes (-S and -s)\n\n";
+ std::exit(1);
+ }
+ if (mAudioTester.getEnabled()
+ && (mAudioBitResolution != AudioInterface::BIT16)
+ && (mAudioBitResolution != AudioInterface::BIT32) ) { // BIT32 not tested but should be ok
+ // BIT24 should work also, but there's a comment saying it's broken right now, so exclude it
+ std::cerr << "*** --examine-audio-delay (-x) ERROR: Only --bitres (-b) 16 and 32 presently supported for audio latency measurement.\n\n";
+ std::exit(1);
+ }
+}
//*******************************************************************************
void Settings::printUsage()
@@ -384,12 +556,12 @@ void Settings::printUsage()
cout << "SoundWIRE group at CCRMA, Stanford University" << endl;
cout << "VERSION: " << gVersion << endl;
cout << "" << endl;
- cout << "Usage: jacktrip [-s|-c host] [options]" << endl;
+ cout << "Usage: jacktrip [-s|-c|-S|-C hostIPAddressOrURL] [options]" << endl;
cout << "" << endl;
cout << "Options: " << endl;
- cout << "REQUIRED ARGUMENTS: " << endl;
- cout << " -s, --server Run in Server Mode" << endl;
- cout << " -c, --client <peer_hostname_or_IP_num> Run in Client Mode" << endl;
+ cout << "REQUIRED ARGUMENTS: One of:" << endl;
+ cout << " -s, --server Run in P2P Server Mode" << endl;
+ cout << " -c, --client <peer_hostname_or_IP_num> Run in P2P Client Mode" << endl;
cout << " -S, --jacktripserver Run in Hub Server Mode" << endl;
cout << " -C, --pingtoserver <peer_name_or_IP> Run in Hub Client Mode" << endl;
cout << endl;
@@ -400,7 +572,7 @@ void Settings::printUsage()
cout << " -w, --wair Run in WAIR Mode" << endl;
cout << " -N, --addcombfilterlength # comb length adjustment for WAIR (default "
<< gDefaultAddCombFilterLength << ")" << endl;
- cout << " -H, --combfilterfeedback # comb feedback adjustment for WAIR (default "
+ cout << " -H, --combfilterfeedback # (roomSize) comb feedback adjustment for WAIR (default "
<< gDefaultCombFilterFeedback << ")" << endl;
#endif // endwhere
cout << " -q, --queue # (2 or more) Queue Buffer Length, in Packet Size (default: "
@@ -411,24 +583,41 @@ void Settings::printUsage()
cout << " -B, --bindport # Set only the bind port number (default: " << gDefaultPort << ")" << endl;
cout << " -P, --peerport # Set only the peer port number (default: " << gDefaultPort << ")" << endl;
cout << " -U, --udpbaseport Set only the server udp base port number (default: 61002)" << endl;
- cout << " -b, --bitres # (8, 16, 24, 32) Audio Bit Rate Resolutions (default: 16)" << endl;
- cout << " -p, --hubpatch # (0, 1, 2, 3, 4) Hub auto audio patch, only has effect if running HUB SERVER mode, 0=server-to-clients, 1=client loopback, 2=clients can hear all clients except themselves, 3=reserved for TUB, 4=full mix (default: 0), i.e. clients auto-connect and hear all clients including themselves" << endl;
+ cout << " -b, --bitres # (8, 16, 24, 32) Audio Bit Rate Resolutions (default: 16, 32 uses floating-point)" << endl;
+ cout << " -p, --hubpatch # (0, 1, 2, 3, 4, 5) Hub auto audio patch, only has effect if running HUB SERVER mode, 0=server-to-clients, 1=client loopback, 2=client fan out/in but not loopback, 3=reserved for TUB, 4=full mix, 5=no auto patching (default: 0)" << endl;
cout << " -z, --zerounderrun Set buffer to zeros when underrun occurs (default: wavetable)" << endl;
+ cout << " -t, --timeout Quit after 10 seconds of no network activity" << endl;
cout << " -l, --loopback Run in Loop-Back Mode" << endl;
cout << " -j, --jamlink Run in JamLink Mode (Connect to a JamLink Box)" << endl;
- cout << " --clientname Change default client name (default: JackTrip)" << endl;
- cout << " --localaddress Change default local host IP address (default: 127.0.0.1)" << endl;
- cout << " --nojackportsconnect Don't connect default audio ports in jack, including not doing hub auto audio patch in HUB SERVER mode." << endl;
+ cout << " -J, --clientname Change default client name (default: JackTrip)" << endl;
+ cout << " -K, --remotename Change default remote client name when connecting to a hub server (the default is derived from this computer's external facing IP address)" << endl;
+ cout << " -L, --localaddress Change default local host IP address (default: 127.0.0.1)" << endl;
+ cout << " -D, --nojackportsconnect Don't connect default audio ports in jack" << endl;
+ cout << " --bufstrategy # (0, 1, 2) Use alternative jitter buffer" << endl;
+ cout << " --broadcast <broadcast_queue> Turn on broadcast output ports with extra queue (requires new jitter buffer)" << endl;
+ cout << " --udprt Use RT thread priority for network I/O" << endl;
+ cout << endl;
+ cout << "OPTIONAL SIGNAL PROCESSING: " << endl;
+ cout << " -f, --effects # | paramString | help Turn on incoming and/or outgoing compressor and/or reverb in Client - see `-f help' for details" << endl;
+ cout << " -O, --overflowlimiting i|o[w]|io[w]|n|help" << endl;
+ cout << " Use audio limiter(s) in Client, i=incoming from network, o=outgoing to network, io=both, n=no limiters, w=warn if limiting (default=n). Say -O help for more." << endl;
+ cout << " -a, --assumednumclients help|# (1,2,...) Assumed number of Clients (sources) mixing at Hub Server (otherwise 2 assumed by -O)" << endl;
cout << endl;
cout << "ARGUMENTS TO USE JACKTRIP WITHOUT JACK:" << endl;
- cout << " --rtaudio Use system's default sound system instead of Jack" << endl;
- cout << " --srate # Set the sampling rate, works on --rtaudio mode only (default: 48000)" << endl;
- cout << " --bufsize # Set the buffer size, works on --rtaudio mode only (default: 128)" << endl;
- cout << " --deviceid # The rtaudio device id --rtaudio mode only (default: 0)" << endl;
+ cout << " -R, --rtaudio Use system's default sound system instead of Jack" << endl;
+ cout << " -T, --srate # Set the sampling rate, works on --rtaudio mode only (default: 48000)" << endl;
+ cout << " -F, --bufsize # Set the buffer size, works on --rtaudio mode only (default: 128)" << endl;
+ cout << " -d, --deviceid # The rtaudio device id --rtaudio mode only (default: 0)" << endl;
cout << endl;
cout << "ARGUMENTS TO DISPLAY IO STATISTICS:" << endl;
cout << " -I, --iostat <time_in_secs> Turn on IO stat reporting with specified interval (in seconds)" << endl;
cout << " -G, --iostatlog <log_file> Save stat log into a file (default: print in stdout)" << endl;
+ cout << " -x, --examine-audio-delay <print_interval_in_secs> | help\n";
+ cout << " Print round-trip audio delay statistics. See `-x help' for details." << endl;
+ cout << endl;
+ cout << "ARGUMENTS TO SIMULATE NETWORK ISSUES:" << endl;
+ cout << " --simloss <rate> Simulate packet loss" << endl;
+ cout << " --simjitter <rate>,<d> Simulate jitter, d is max delay in packets" << endl;
cout << endl;
cout << "HELP ARGUMENTS: " << endl;
cout << " -v, --version Prints Version Number" << endl;
@@ -439,211 +628,208 @@ void Settings::printUsage()
//*******************************************************************************
-void Settings::startJackTrip()
+UdpHubListener *Settings::getConfiguredHubServer()
{
-
if ((mBindPortNum < gBindPortLow) || (mBindPortNum > gBindPortHigh))
std::cout << "BindPort: "<< mBindPortNum << " outside range" << std::endl;
- /// \todo Change this, just here to test
- if ( mJackTripServer ) {
- if (gVerboseFlag) std::cout << "JackTrip HUB SERVER TCP Bind Port: " << mBindPortNum << std::endl;
- UdpHubListener* udpmaster = new UdpHubListener(mBindPortNum,mServerUdpPortNum);
- udpmaster->setSettings(this);
+ if (gVerboseFlag) std::cout << "JackTrip HUB SERVER TCP Bind Port: " << mBindPortNum << std::endl;
+ UdpHubListener *udpHub = new UdpHubListener(mBindPortNum, mServerUdpPortNum);
+ //udpHub->setSettings(this);
#ifdef WAIR // WAIR
- udpmaster->setWAIR(mWAIR);
+ udpHub->setWAIR(mWAIR);
#endif // endwhere
- udpmaster->setHubPatch(mHubConnectionMode);
- udpmaster->setConnectDefaultAudioPorts(mConnectDefaultAudioPorts);
- if (gVerboseFlag) std::cout << "Settings:startJackTrip before udpmaster->start" << std::endl;
- // Set buffers to zero when underrun
- if ( mUnderrrunZero ) {
- cout << "Setting buffers to zero when underrun..." << endl;
- cout << gPrintSeparator << std::endl;
- udpmaster->setUnderRunMode(JackTrip::ZEROS);
- }
- udpmaster->setBufferQueueLength(mBufferQueueLength);
- udpmaster->start();
-
- //---Thread Pool Test--------------------------------------------
- /*
- cout << "BEFORE START" << endl;
- ThreadPoolTest* thtest = new ThreadPoolTest();
- // QThreadPool takes ownership and deletes 'hello' automatically
- QThreadPool::globalInstance()->start(thtest);
-
- cout << "AFTER START" << endl;
- sleep(2);
- thtest->stop();
- QThreadPool::globalInstance()->waitForDone();
- */
- //---------------------------------------------------------------
+ udpHub->setHubPatch(mHubConnectionMode);
+ if (mHubConnectionMode == JackTrip::NOAUTO) {
+ udpHub->setConnectDefaultAudioPorts(false);
+ } else {
+ udpHub->setConnectDefaultAudioPorts(mConnectDefaultAudioPorts);
}
+ // Set buffers to zero when underrun
+ if ( mUnderrunMode == JackTrip::ZEROS ) {
+ cout << "Setting buffers to zero when underrun..." << endl;
+ cout << gPrintSeparator << std::endl;
+ udpHub->setUnderRunMode(mUnderrunMode);
+ }
+ udpHub->setBufferQueueLength(mBufferQueueLength);
+
+ udpHub->setBufferStrategy(mBufferStrategy);
+ udpHub->setNetIssuesSimulation(mSimulatedLossRate,
+ mSimulatedJitterRate, mSimulatedDelayRel);
+ udpHub->setBroadcast(mBroadcastQueue);
+ udpHub->setUseRtUdpPriority(mUseRtUdpPriority);
+
+ if (mIOStatTimeout > 0) {
+ udpHub->setIOStatTimeout(mIOStatTimeout);
+ udpHub->setIOStatStream(mIOStatStream);
+ }
+ return udpHub;
+}
- else {
-
- //JackTrip jacktrip(mJackTripMode, mDataProtocol, mNumChans,
- // mBufferQueueLength, mAudioBitResolution);
+JackTrip *Settings::getConfiguredJackTrip()
+{
#ifdef WAIR // WAIR
- if (gVerboseFlag) std::cout << "Settings:startJackTrip mNumNetRevChans = " << mNumNetRevChans << std::endl;
+ if (gVerboseFlag) std::cout << "Settings:startJackTrip mNumNetRevChans = " << mNumNetRevChans << std::endl;
#endif // endwhere
- if (gVerboseFlag) std::cout << "Settings:startJackTrip before new JackTrip" << std::endl;
- mJackTrip = new JackTrip(mJackTripMode, mDataProtocol, mNumChans,
- #ifdef WAIR // wair
- mNumNetRevChans,
- #endif // endwhere
- mBufferQueueLength, mRedundancy, mAudioBitResolution,
- /*DataProtocol::packetHeaderTypeT PacketHeaderType = */DataProtocol::DEFAULT,
- /*underrunModeT UnderRunMode = */ mUnderRunMode,
- /* int receiver_bind_port = */ gDefaultPort,
- /*int sender_bind_port = */ gDefaultPort,
- /*int receiver_peer_port = */ gDefaultPort,
- /* int sender_peer_port = */ gDefaultPort,
- mPeerPortNum
- );
-
- // Set connect or not default audio ports. Only work for jack
- mJackTrip->setConnectDefaultAudioPorts(mConnectDefaultAudioPorts);
-
- // Connect Signals and Slots
- QObject::connect(mJackTrip, SIGNAL( signalProcessesStopped() ),
- this, SLOT( slotExitProgram() ));
-
- // Change client name if different from default
- if (mClientName != NULL) {
- mJackTrip->setClientName(mClientName);
- }
+ if (gVerboseFlag) std::cout << "Settings:startJackTrip before new JackTrip" << std::endl;
+ JackTrip *jackTrip = new JackTrip(mJackTripMode, mDataProtocol, mNumChans,
+#ifdef WAIR // wair
+ mNumNetRevChans,
+#endif // endwhere
+ mBufferQueueLength, mRedundancy, mAudioBitResolution,
+ /*DataProtocol::packetHeaderTypeT PacketHeaderType = */DataProtocol::DEFAULT,
+ /*underrunModeT UnderRunMode = */ mUnderrunMode,
+ /* int receiver_bind_port = */ mBindPortNum,
+ /*int sender_bind_port = */ mBindPortNum,
+ /*int receiver_peer_port = */ mPeerPortNum,
+ /* int sender_peer_port = */ mPeerPortNum,
+ mPeerPortNum
+ );
+ // Set connect or not default audio ports. Only work for jack
+ jackTrip->setConnectDefaultAudioPorts(mConnectDefaultAudioPorts);
+
+ // Change client name if different from default
+ if (!mClientName.isEmpty()) {
+ jackTrip->setClientName(mClientName);
+ }
- // Set buffers to zero when underrun
- if ( mUnderrrunZero ) {
- cout << "Setting buffers to zero when underrun..." << endl;
- cout << gPrintSeparator << std::endl;
- mJackTrip->setUnderRunMode(JackTrip::ZEROS);
- } else {
- cout << "Setting buffers to wavetable when underrun..." << endl;
- cout << gPrintSeparator << std::endl;
- mJackTrip->setUnderRunMode(JackTrip::WAVETABLE);
- }
+ if (!mRemoteClientName.isEmpty() && (mJackTripMode == JackTrip::CLIENTTOPINGSERVER)) {
+ jackTrip->setRemoteClientName(mRemoteClientName);
+ }
- // Set peer address in server mode
- if ( mJackTripMode == JackTrip::CLIENT || mJackTripMode == JackTrip::CLIENTTOPINGSERVER ) {
- mJackTrip->setPeerAddress(mPeerAddress.toLatin1().data()); }
-
- // if(mLocalAddress!=QString()) // default
- // mJackTrip->setLocalAddress(QHostAddress(mLocalAddress.toLatin1().data()));
- // else
- // mJackTrip->setLocalAddress(QHostAddress::Any);
-
- // Set Ports
- //cout << "SETTING ALL PORTS" << endl;
- if (gVerboseFlag) std::cout << "Settings:startJackTrip before mJackTrip->setBindPorts" << std::endl;
- mJackTrip->setBindPorts(mBindPortNum);
- if (gVerboseFlag) std::cout << "Settings:startJackTrip before mJackTrip->setPeerPorts" << std::endl;
- mJackTrip->setPeerPorts(mPeerPortNum);
-
- // Set in JamLink Mode
- if ( mJamLink ) {
- cout << "Running in JamLink Mode..." << endl;
- cout << gPrintSeparator << std::endl;
- mJackTrip->setPacketHeaderType(DataProtocol::JAMLINK);
- }
+ // Set buffers to zero when underrun (Actual setting is handled in constructor.)
+ if (mUnderrunMode == JackTrip::ZEROS) {
+ cout << "Setting buffers to zero when underrun..." << endl;
+ cout << gPrintSeparator << std::endl;
+ }
- // Set in EmptyHeader Mode
- if ( mEmptyHeader ) {
- cout << "Running in EmptyHeader Mode..." << endl;
- cout << gPrintSeparator << std::endl;
- mJackTrip->setPacketHeaderType(DataProtocol::EMPTY);
- }
+ jackTrip->setStopOnTimeout(mStopOnTimeout);
+
+ // Set peer address in server mode
+ if (mJackTripMode == JackTrip::CLIENT || mJackTripMode == JackTrip::CLIENTTOPINGSERVER) {
+ jackTrip->setPeerAddress(mPeerAddress); }
+
+ // if(mLocalAddress!=QString()) // default
+ // mJackTrip->setLocalAddress(QHostAddress(mLocalAddress.toLatin1().data()));
+ // else
+ // mJackTrip->setLocalAddress(QHostAddress::Any);
+
+ // Set Ports - Done in constructor now.
+ //cout << "SETTING ALL PORTS" << endl;
+ /*if (gVerboseFlag) std::cout << "Settings:startJackTrip before mJackTrip->setBindPorts" << std::endl;
+ jackTrip->setBindPorts(mBindPortNum);
+ if (gVerboseFlag) std::cout << "Settings:startJackTrip before mJackTrip->setPeerPorts" << std::endl;
+ jackTrip->setPeerPorts(mPeerPortNum);*/
+
+ // Set in JamLink Mode
+ if ( mJamLink ) {
+ cout << "Running in JamLink Mode..." << endl;
+ cout << gPrintSeparator << std::endl;
+ jackTrip->setPacketHeaderType(DataProtocol::JAMLINK);
+ }
- // Set RtAudio
+ // Set in EmptyHeader Mode
+ if (mEmptyHeader) {
+ cout << "Running in EmptyHeader Mode..." << endl;
+ cout << gPrintSeparator << std::endl;
+ jackTrip->setPacketHeaderType(DataProtocol::EMPTY);
+ }
+
+ // Set RtAudio
#ifdef __RT_AUDIO__
- if (!mUseJack) {
- mJackTrip->setAudiointerfaceMode(JackTrip::RTAUDIO);
- }
+ if (!mUseJack) {
+ mJackTrip->setAudiointerfaceMode(JackTrip::RTAUDIO);
+ }
#endif
- // Chanfe default Sampling Rate
- if (mChanfeDefaultSR) {
- mJackTrip->setSampleRate(mSampleRate);
- }
+ // Chanfe default Sampling Rate
+ if (mChanfeDefaultSR) {
+ jackTrip->setSampleRate(mSampleRate);
+ }
- // Chanfe defualt device ID
- if (mChanfeDefaultID) {
- mJackTrip->setDeviceID(mDeviceID);
- }
+ // Chanfe defualt device ID
+ if (mChanfeDefaultID) {
+ jackTrip->setDeviceID(mDeviceID);
+ }
- // Chanfe default Buffer Size
- if (mChanfeDefaultBS) {
- mJackTrip->setAudioBufferSizeInSamples(mAudioBufferSize);
- }
+ // Chanfe default Buffer Size
+ if (mChanfeDefaultBS) {
+ jackTrip->setAudioBufferSizeInSamples(mAudioBufferSize);
+ }
+ jackTrip->setBufferStrategy(mBufferStrategy);
+ jackTrip->setNetIssuesSimulation(mSimulatedLossRate,
+ mSimulatedJitterRate, mSimulatedDelayRel);
+ jackTrip->setBroadcast(mBroadcastQueue);
+ jackTrip->setUseRtUdpPriority(mUseRtUdpPriority);
+
+ // Add Plugins
+ if (mLoopBack) {
+ cout << "Running in Loop-Back Mode..." << endl;
+ cout << gPrintSeparator << std::endl;
+ //std::tr1::shared_ptr<LoopBack> loopback(new LoopBack(mNumChans));
+ //mJackTrip->appendProcessPlugin(loopback.get());
+
+#if 0 // previous technique:
+ LoopBack* loopback = new LoopBack(mNumChans);
+ jackTrip->appendProcessPlugin(loopback);
+#else // simpler method ( see AudioInterface.cpp callback() ):
+ jackTrip->setLoopBack(true);
+#endif
- // Add Plugins
- if ( mLoopBack ) {
- cout << "Running in Loop-Back Mode..." << endl;
- cout << gPrintSeparator << std::endl;
- //std::tr1::shared_ptr<LoopBack> loopback(new LoopBack(mNumChans));
- //mJackTrip->appendProcessPlugin(loopback.get());
-
- LoopBack* loopback = new LoopBack(mNumChans);
- mJackTrip->appendProcessPlugin(loopback);
-
- // ----- Test Karplus Strong -----------------------------------
- //std::tr1::shared_ptr<NetKS> loopback(new NetKS());
- //mJackTrip->appendProcessPlugin(loopback);
- //loopback->play();
- //NetKS* netks = new NetKS;
- //mJackTrip->appendProcessPlugin(netks);
- //netks->play();
- // -------------------------------------------------------------
- }
+ // ----- Test Karplus Strong -----------------------------------
+ //std::tr1::shared_ptr<NetKS> loopback(new NetKS());
+ //mJackTrip->appendProcessPlugin(loopback);
+ //loopback->play();
+ //NetKS* netks = new NetKS;
+ //mJackTrip->appendProcessPlugin(netks);
+ //netks->play();
+ // -------------------------------------------------------------
+ }
+
+ if (mIOStatTimeout > 0) {
+ jackTrip->setIOStatTimeout(mIOStatTimeout);
+ jackTrip->setIOStatStream(mIOStatStream);
+ }
+
+ jackTrip->setAudioTesterP(&mAudioTester);
+
+ // Allocate audio effects in client, if any:
+ int nReservedChans = mAudioTester.getEnabled() ? 1 : 0; // no fx allowed on tester channel
+ std::vector<ProcessPlugin*> outgoingEffects = mEffects.allocateOutgoingEffects(mNumChans-nReservedChans);
+ for (auto p : outgoingEffects) {
+ jackTrip->appendProcessPluginToNetwork( p );
+ }
+ std::vector<ProcessPlugin*> incomingEffects = mEffects.allocateIncomingEffects(mNumChans-nReservedChans);
+ for (auto p : incomingEffects) {
+ jackTrip->appendProcessPluginFromNetwork( p );
+ }
#ifdef WAIR // WAIR
- if ( mWAIR ) {
- cout << "Running in WAIR Mode..." << endl;
- cout << gPrintSeparator << std::endl;
- switch ( mNumNetRevChans )
- {
- case 16 :
- {
- mJackTrip->appendProcessPlugin(new ap8x2(mNumChans)); // plugin slot 0
- /////////////////////////////////////////////////////////
- Stk16* plugin = new Stk16(mNumNetRevChans);
- plugin->Stk16::initCombClient(mClientAddCombLen, mClientRoomSize);
- mJackTrip->appendProcessPlugin(plugin); // plugin slot 1
- }
- break;
- default:
- throw std::invalid_argument("Settings: mNumNetRevChans doesn't correspond to Faust plugin");
- break;
- }
+ if ( mWAIR ) {
+ cout << "Running in WAIR Mode..." << endl;
+ cout << gPrintSeparator << std::endl;
+ switch ( mNumNetRevChans )
+ {
+ case 16 :
+ {
+ jackTrip->appendProcessPluginFromNetwork(new ap8x2(mNumChans)); // plugin slot 0
+ /////////////////////////////////////////////////////////
+ Stk16* plugin = new Stk16(mNumNetRevChans);
+ plugin->Stk16::initCombClient(mClientAddCombLen, mClientRoomSize);
+ jackTrip->appendProcessPluginFromNetwork(plugin); // plugin slot 1
}
-#endif // endwhere
-
- // Start JackTrip
- if (gVerboseFlag) std::cout << "Settings:startJackTrip before mJackTrip->startProcess" << std::endl;
- mJackTrip->startProcess(
- #ifdef WAIRTOHUB // WAIR
- 0 // for WAIR compatibility, ID in jack client name
- #endif // endwhere
- );
- if (0 < getIOStatTimeout()) {
- mJackTrip->startIOStatTimer(getIOStatTimeout(), getIOStatStream());
+ break;
+ default:
+ throw std::invalid_argument("Settings: mNumNetRevChans doesn't correspond to Faust plugin");
+ break;
+ }
+ break;
+ default:
+ throw std::invalid_argument("Settings: mNumNetRevChans doesn't correspond to Faust plugin");
+ break;
}
- // if (gVerboseFlag) std::cout << "Settings:startJackTrip before mJackTrip->start" << std::endl;
- // this is a noop
- // mJackTrip->start();
-
- /*
- sleep(10);
- cout << "Stoping JackTrip..." << endl;
- mJackTrip->stop();
- */
}
-}
-
+#endif // endwhere
-//*******************************************************************************
-void Settings::stopJackTrip()
-{
- mJackTrip->stop();
+ return jackTrip;
}
diff --git a/src/Settings.h b/src/Settings.h
index 9856bf2..569b451 100644
--- a/src/Settings.h
+++ b/src/Settings.h
@@ -41,6 +41,7 @@
#include <cstdlib>
#include <fstream>
+#include <vector>
#include "DataProtocol.h"
@@ -49,10 +50,14 @@
#endif //__NO_JACK__
#include "JackTrip.h"
+#include "UdpHubListener.h"
+
+#include "Effects.h"
+#include "AudioTester.h"
/** \brief Class to set usage options and parse settings from input
*/
-class Settings : public QThread
+class Settings : public QObject
{
Q_OBJECT;
@@ -63,29 +68,16 @@ public:
/// \brief Parses command line input
void parseInput(int argc, char** argv);
- void startJackTrip();
- void stopJackTrip();
+ UdpHubListener *getConfiguredHubServer();
+ JackTrip *getConfiguredJackTrip();
/// \brief Prints usage help
void printUsage();
bool getLoopBack() { return mLoopBack; }
- int getIOStatTimeout() const {return mIOStatTimeout;}
- const std::ostream& getIOStatStream() const
- {
- return mIOStatStream.is_open() ? (std::ostream&)mIOStatStream : std::cout;
- }
-
-
-public slots:
- void slotExitProgram()
- {
- std::cerr << "Exiting JackTrip..." << std::endl;
- std::exit(1);
- }
+ bool isHubServer() { return mJackTripServer; }
private:
- JackTrip* mJackTrip; ///< JackTrip class
JackTrip::jacktripModeT mJackTripMode; ///< JackTrip::jacktripModeT
JackTrip::dataProtocolT mDataProtocol; ///< Data Protocol
int mNumChans; ///< Number of Channels (inputs = outputs)
@@ -95,9 +87,11 @@ private:
int mBindPortNum; ///< Bind Port Number
int mPeerPortNum; ///< Peer Port Number
int mServerUdpPortNum;
- char* mClientName; ///< JackClient Name
- bool mUnderrrunZero; ///< Use Underrun to Zero mode
- JackTrip::underrunModeT mUnderRunMode;
+ QString mClientName; ///< JackClient Name
+ QString mRemoteClientName;
+ JackTrip::underrunModeT mUnderrunMode; ///< Underrun mode
+ bool mStopOnTimeout; /// < Stop jacktrip after 10 second network timeout
+ int mBufferStrategy;
#ifdef WAIR // wair
int mNumNetRevChans; ///< Number of Network Audio Channels (net comb filters)
@@ -122,7 +116,14 @@ private:
unsigned int mHubConnectionMode;
bool mConnectDefaultAudioPorts; ///< Connect or not jack audio ports
int mIOStatTimeout;
- std::ofstream mIOStatStream;
+ QSharedPointer<std::ofstream> mIOStatStream;
+ Effects mEffects;
+ double mSimulatedLossRate;
+ double mSimulatedJitterRate;
+ double mSimulatedDelayRel;
+ int mBroadcastQueue;
+ bool mUseRtUdpPriority;
+ AudioTester mAudioTester;
};
#endif
diff --git a/src/UdpDataProtocol.cpp b/src/UdpDataProtocol.cpp
index 85738a6..3680185 100644
--- a/src/UdpDataProtocol.cpp
+++ b/src/UdpDataProtocol.cpp
@@ -53,6 +53,8 @@
#endif
#if defined (__LINUX__) || (__MAC_OSX__)
#include <sys/socket.h> // for POSIX Sockets
+#include <unistd.h>
+#include <sys/fcntl.h>
#endif
using std::cout; using std::endl;
@@ -72,7 +74,9 @@ UdpDataProtocol::UdpDataProtocol(JackTrip* jacktrip, const runModeT runmode,
mBindPort(bind_port), mPeerPort(peer_port),
mRunMode(runmode),
mAudioPacket(NULL), mFullPacket(NULL),
- mUdpRedundancyFactor(udp_redundancy_factor)
+ mUdpRedundancyFactor(udp_redundancy_factor),
+ mControlPacketSize(63),
+ mStopSignalSent(false)
{
mStopped = false;
mIPv6 = false;
@@ -85,6 +89,9 @@ UdpDataProtocol::UdpDataProtocol(JackTrip* jacktrip, const runModeT runmode,
QObject::connect(this, SIGNAL(signalWaitingTooLong(int)),
jacktrip, SLOT(slotUdpWaitingTooLongClientGoneProbably(int)), Qt::QueuedConnection);
}
+ mSimulatedLossRate = 0.0;
+ mSimulatedJitterRate = 0.0;
+ mSimulatedJitterMaxDelay = 0.0;
}
@@ -93,6 +100,13 @@ UdpDataProtocol::~UdpDataProtocol()
{
delete[] mAudioPacket;
delete[] mFullPacket;
+ if (mRunMode == RECEIVER) {
+#ifdef __WIN_32__
+ closesocket(mSocket);
+#else
+ ::close(mSocket);
+#endif
+ }
wait();
}
@@ -121,7 +135,7 @@ void UdpDataProtocol::setPeerAddress(const char* peerHostOrIP)
if ( mPeerAddress.protocol() == QAbstractSocket::IPv6Protocol ) {
mIPv6 = true;
} else if ( mPeerAddress.protocol() != QAbstractSocket::IPv4Protocol ) {
- QString error_message = "Incorrect presentation format address\n '";
+ QString error_message = "Incorrect presentation format address\n'";
error_message.append(peerHostOrIP);
error_message.append("' is not a valid IP address or Host Name");
//std::cerr << "ERROR: Incorrect presentation format address" << endl;
@@ -163,7 +177,7 @@ void UdpDataProtocol::setSocket(int &socket)
if (socket == -1) {
#endif
try {
- if (gVerboseFlag) std::cout << " UdpDataProtocol:run" << mRunMode << " before bindSocket(UdpSocket)" << std::endl;
+ if (gVerboseFlag) std::cout << " UdpDataProtocol:run" << mRunMode << " before bindSocket" << std::endl;
socket = bindSocket(); // Bind Socket
} catch ( const std::exception & e ) {
emit signalError( e.what() );
@@ -316,11 +330,29 @@ int UdpDataProtocol::bindSocket()
//*******************************************************************************
-int UdpDataProtocol::receivePacket(QUdpSocket& UdpSocket, char* buf, const size_t n)
+int UdpDataProtocol::receivePacket(char* buf, const size_t n)
{
// Block until There's something to read
- while ( (UdpSocket.pendingDatagramSize() < n) && !mStopped ) { QThread::usleep(100); }
- int n_bytes = UdpSocket.readDatagram(buf, n);
+ while ( !datagramAvailable() && !mStopped ) {
+ QThread::usleep(100);
+ }
+ int n_bytes = ::recv(mSocket, buf, n, 0);
+ if (n_bytes == mControlPacketSize) {
+ //Control signal (currently just check for exit packet);
+ bool exit = true;
+ for (int i = 0; i < mControlPacketSize; i++) {
+ if (buf[i] != char(0xff)) {
+ exit = false;
+ i = mControlPacketSize;
+ }
+ }
+ if (exit && !mStopSignalSent) {
+ mStopSignalSent = true;
+ emit signalCeaseTransmission("Peer Stopped");
+ std::cout << "Peer Stopped" <<std::endl;
+ }
+ return 0;
+ }
return n_bytes;
}
@@ -358,15 +390,24 @@ int UdpDataProtocol::sendPacket(const char* buf, const size_t n)
//*******************************************************************************
-void UdpDataProtocol::getPeerAddressFromFirstPacket(QUdpSocket& UdpSocket,
- QHostAddress& peerHostAddress,
+void UdpDataProtocol::getPeerAddressFromFirstPacket(QHostAddress& peerHostAddress,
uint16_t& port)
{
- while ( !UdpSocket.hasPendingDatagrams() ) {
+ while ( !datagramAvailable() ) {
msleep(100);
}
char buf[1];
- UdpSocket.readDatagram(buf, 1, &peerHostAddress, &port);
+
+ struct sockaddr_storage addr;
+ std::memset(&addr, 0, sizeof(addr));
+ socklen_t sa_len = sizeof(addr);
+ ::recvfrom(mSocket, buf, 1, 0, (struct sockaddr*) &addr, &sa_len);
+ peerHostAddress.setAddress((struct sockaddr*) &addr);
+ if (mIPv6) {
+ port = ((struct sockaddr_in6*) &addr)->sin6_port;
+ } else {
+ port = ((struct sockaddr_in*) &addr)->sin_port;
+ }
}
@@ -388,19 +429,17 @@ void UdpDataProtocol::run()
// mJackTrip, SLOT(slotStopProcesses()),
// Qt::QueuedConnection);
- //Wrap our socket in a QUdpSocket object if we're the receiver, for convenience.
- //If we're the sender, we'll just write directly to our socket.
- QUdpSocket UdpSocket;
if (mRunMode == RECEIVER) {
- if (mIPv6) {
- UdpSocket.setSocketDescriptor(mSocket, QUdpSocket::BoundState,
- QUdpSocket::ReadOnly);
- } else {
- UdpSocket.setSocketDescriptor(mSocket, QUdpSocket::ConnectedState,
- QUdpSocket::ReadOnly);
- }
cout << "UDP Socket Receiving in Port: " << mBindPort << endl;
cout << gPrintSeparator << endl;
+ //Make sure our socket is in non-blocking mode.
+#ifdef __WIN_32__
+ u_long nonblock = 1;
+ ioctlsocket(mSocket, FIONBIO, &nonblock);
+#else
+ int flags = ::fcntl(mSocket, F_GETFL, 0);
+ ::fcntl(mSocket, F_SETFL, flags | O_NONBLOCK);
+#endif
}
if (gVerboseFlag) std::cout << " UdpDataProtocol:run" << mRunMode << " before Setup Audio Packet buffer, Full Packet buffer, Redundancy Variables" << std::endl;
@@ -409,6 +448,9 @@ void UdpDataProtocol::run()
//cout << "audio_packet_size: " << audio_packet_size << endl;
mAudioPacket = new int8_t[audio_packet_size];
std::memset(mAudioPacket, 0, audio_packet_size); // set buffer to 0
+ mBuffer.resize(audio_packet_size, 0);
+ mChans = mJackTrip->getNumChannels();
+ mSmplSize = mJackTrip->getAudioBitResolution() / 8;
// Setup Full Packet buffer
int full_packet_size = mJackTrip->getPacketSizeInBytes();
@@ -425,14 +467,15 @@ void UdpDataProtocol::run()
// (Algorithm explained at the end of this file)
// ---------------------------------------------
int full_redundant_packet_size = full_packet_size * mUdpRedundancyFactor;
- int8_t* full_redundant_packet;
- full_redundant_packet = new int8_t[full_redundant_packet_size];
- std::memset(full_redundant_packet, 0, full_redundant_packet_size); // Initialize to 0
+ int8_t* full_redundant_packet = NULL;
// Set realtime priority (function in jacktrip_globals.h)
if (gVerboseFlag) std::cout << " UdpDataProtocol:run" << mRunMode << " before setRealtimeProcessPriority()" << std::endl;
//std::cout << "Experimental version -- not using setRealtimeProcessPriority()" << std::endl;
- //setRealtimeProcessPriority();
+ // Anton Runov: making setRealtimeProcessPriority optional
+ if (mUseRtPriority) {
+ setRealtimeProcessPriority();
+ }
/////////////////////
// to see thread priorities
@@ -507,24 +550,31 @@ void UdpDataProtocol::run()
if (gVerboseFlag) std::cout << " UdpDataProtocol:run" << mRunMode << " before !UdpSocket.hasPendingDatagrams()" << std::endl;
std::cout << "Waiting for Peer..." << std::endl;
// This blocks waiting for the first packet
- while ( !UdpSocket.hasPendingDatagrams() ) {
+ while ( !datagramAvailable() ) {
if (mStopped) { return; }
QThread::msleep(100);
if (gVerboseFlag) std::cout << "100ms " << std::flush;
}
- int first_packet_size = UdpSocket.pendingDatagramSize();
- // The following line is the same as
- int8_t* first_packet = new int8_t[first_packet_size];
- /// \todo fix this to avoid memory leaks
- // but avoids memory leaks
- //std::tr1::shared_ptr<int8_t> first_packet(new int8_t[first_packet_size]);
- receivePacket( UdpSocket, reinterpret_cast<char*>(first_packet), first_packet_size);
+ full_redundant_packet_size = 0x10000; // max UDP datagram size
+ full_redundant_packet = new int8_t[full_redundant_packet_size];
+ full_redundant_packet_size = receivePacket(reinterpret_cast<char*>(full_redundant_packet), full_redundant_packet_size);
// Check that peer has the same audio settings
if (gVerboseFlag) std::cout << std::endl << " UdpDataProtocol:run" << mRunMode << " before mJackTrip->checkPeerSettings()" << std::endl;
- mJackTrip->checkPeerSettings(first_packet);
+ mJackTrip->checkPeerSettings(full_redundant_packet);
+
+ int peer_chans = mJackTrip->getPeerNumChannels(full_redundant_packet);
+ full_packet_size = mJackTrip->getHeaderSizeInBytes()
+ + mJackTrip->getPeerBufferSize(full_redundant_packet) * peer_chans * mSmplSize;
+ /*
+ cout << "peer sizes: " << mJackTrip->getHeaderSizeInBytes()
+ << " + " << mJackTrip->getPeerBufferSize(full_redundant_packet)
+ << " * " << mJackTrip->getNumChannels() << " * " << (int)mJackTrip->getAudioBitResolution()/8 << endl;
+ cout << "full_packet_size: " << full_packet_size << " / " << mJackTrip->getPacketSizeInBytes() << endl;
+ cout << "full_redundant_packet_size: " << full_redundant_packet_size << endl;
+ // */
+
if (gVerboseFlag) std::cout << "step 7" << std::endl;
if (gVerboseFlag) std::cout << " UdpDataProtocol:run" << mRunMode << " before mJackTrip->parseAudioPacket()" << std::endl;
- mJackTrip->parseAudioPacket(mFullPacket, mAudioPacket);
std::cout << "Received Connection from Peer!" << std::endl;
emit signalReceivedConnectionFromPeer();
@@ -538,6 +588,8 @@ void UdpDataProtocol::run()
mTotCount = 0;
mLostCount = 0;
mOutOfOrderCount = 0;
+ mLastOutOfOrderCount = 0;
+ mInitialState = true;
mRevivedCount = 0;
mStatCount = 0;
@@ -550,7 +602,7 @@ void UdpDataProtocol::run()
// arrive for a longer time
//timeout = UdpSocket.waitForReadyRead(30);
// timeout = cc unused!
- waitForReady(UdpSocket, 60000); //60 seconds
+ waitForReady(60000); //60 seconds
// OLD CODE WITHOUT REDUNDANCY----------------------------------------------------
/*
@@ -565,8 +617,7 @@ void UdpDataProtocol::run()
mJackTrip->writeAudioBuffer(mAudioPacket);
*/
//----------------------------------------------------------------------------------
- receivePacketRedundancy(UdpSocket,
- full_redundant_packet,
+ receivePacketRedundancy(full_redundant_packet,
full_redundant_packet_size,
full_packet_size,
current_seq_num,
@@ -576,7 +627,9 @@ void UdpDataProtocol::run()
break; }
case SENDER : {
- while ( !mStopped )
+ full_redundant_packet = new int8_t[full_redundant_packet_size];
+ std::memset(full_redundant_packet, 0, full_redundant_packet_size); // Initialize to 0
+ while ( !mStopped && !JackTrip::sSigInt && !JackTrip::sJackStopped )
{
// OLD CODE WITHOUT REDUNDANCY -----------------------------------------------------
/*
@@ -592,24 +645,34 @@ void UdpDataProtocol::run()
full_redundant_packet_size,
full_packet_size);
}
+
+ // Send exit packet (with 1 redundant packet).
+ cout << "sending exit packet" << endl;
+ QByteArray exitPacket = QByteArray(mControlPacketSize, 0xff);
+ sendPacket(exitPacket.constData(), mControlPacketSize);
+ sendPacket(exitPacket.constData(), mControlPacketSize);
+ emit signalCeaseTransmission();
break; }
}
+
+ if (NULL != full_redundant_packet) {
+ delete[] full_redundant_packet;
+ full_redundant_packet = NULL;
+ }
}
//*******************************************************************************
//bool
-void UdpDataProtocol::waitForReady(QUdpSocket& UdpSocket, int timeout_msec)
+void UdpDataProtocol::waitForReady(int timeout_msec)
{
int loop_resolution_usec = 100; // usecs to wait on each loop
int emit_resolution_usec = 10000; // 10 milliseconds
int timeout_usec = timeout_msec * 1000;
int elapsed_time_usec = 0; // Ellapsed time in milliseconds
- while ( ( !(
- UdpSocket.hasPendingDatagrams() &&
- (UdpSocket.pendingDatagramSize() > 0)
- ) && (elapsed_time_usec <= timeout_usec) )
+ while ( !datagramAvailable()
+ && (elapsed_time_usec <= timeout_usec)
&& !mStopped ){
// if (mStopped) { return false; }
QThread::usleep(loop_resolution_usec);
@@ -635,13 +698,13 @@ void UdpDataProtocol::printUdpWaitedTooLong(int wait_msec)
int wait_time = 30; // msec
if ( !(wait_msec%wait_time) ) {
std::cerr << "UDP waiting too long (more than " << wait_time << "ms) for " << mPeerAddress.toString().toStdString() << "..." << endl;
+ emit signalUdpWaitingTooLong();
}
}
//*******************************************************************************
-void UdpDataProtocol::receivePacketRedundancy(QUdpSocket& UdpSocket,
- int8_t* full_redundant_packet,
+void UdpDataProtocol::receivePacketRedundancy(int8_t* full_redundant_packet,
int full_redundant_packet_size,
int full_packet_size,
uint16_t& current_seq_num,
@@ -649,19 +712,41 @@ void UdpDataProtocol::receivePacketRedundancy(QUdpSocket& UdpSocket,
uint16_t& newer_seq_num)
{
// This is blocking until we get a packet...
- receivePacket( UdpSocket, reinterpret_cast<char*>(full_redundant_packet),
- full_redundant_packet_size);
+ if (receivePacket( reinterpret_cast<char*>(full_redundant_packet),
+ full_redundant_packet_size) == 0) {
+ return;
+ }
+
+ if (0.0 < mSimulatedLossRate || 0.0 < mSimulatedJitterRate) {
+ double x = mUniformDist(mRndEngine);
+ // Drop packets
+ x -= mSimulatedLossRate;
+ if (0 > x) {
+ return;
+ }
+ // Delay packets
+ x -= mSimulatedJitterRate;
+ if (0 > x) {
+ usleep(mUniformDist(mRndEngine) * mSimulatedJitterMaxDelay * 1e6);
+ }
+ }
// Get Packet Sequence Number
newer_seq_num =
mJackTrip->getPeerSequenceNumber(full_redundant_packet);
current_seq_num = newer_seq_num;
- if (0 != last_seq_num) {
- int16_t lost = newer_seq_num - last_seq_num - 1;
- if (0 > lost) {
+ int16_t lost = 0;
+ if (!mInitialState) {
+ lost = newer_seq_num - last_seq_num - 1;
+ if (0 > lost || 1000 < lost) {
// Out of order packet, should be ignored
++mOutOfOrderCount;
+ if (5 < ++mLastOutOfOrderCount) {
+ mInitialState = true;
+ mStatCount = 0;
+ mTotCount = 0;
+ }
return;
}
else if (0 != lost) {
@@ -669,6 +754,8 @@ void UdpDataProtocol::receivePacketRedundancy(QUdpSocket& UdpSocket,
}
mTotCount += 1 + lost;
}
+ mLastOutOfOrderCount = 0;
+ mInitialState = false;
//cout << current_seq_num << " ";
int redun_last_index = 0;
@@ -687,15 +774,38 @@ void UdpDataProtocol::receivePacketRedundancy(QUdpSocket& UdpSocket,
mRevivedCount += redun_last_index;
//cout << endl;
+ int peer_chans = mJackTrip->getPeerNumChannels(full_redundant_packet);
+ int N = mJackTrip->getPeerBufferSize(full_redundant_packet);
+ int host_buf_size = N * mChans * mSmplSize;
+ int hdr_size = mJackTrip->getHeaderSizeInBytes();
+ int gap_size = mInitialState ? 0 : (lost - redun_last_index) * host_buf_size;
+
last_seq_num = newer_seq_num; // Save last read packet
+ if ((int)mBuffer.size() < host_buf_size) {
+ mBuffer.resize(host_buf_size, 0);
+ }
// Send to audio all available audio packets, in order
for (int i = redun_last_index; i>=0; i--) {
- memcpy(mFullPacket,
- full_redundant_packet + (i*full_packet_size),
- full_packet_size);
- mJackTrip->parseAudioPacket(mFullPacket, mAudioPacket);
- mJackTrip->writeAudioBuffer(mAudioPacket);
+ int8_t* src = full_redundant_packet + (i*full_packet_size) + hdr_size;
+ if (1 != mChans) {
+ // Convert packet's non-interleaved layout to interleaved one used internally
+ int8_t* dst = mBuffer.data();
+ int C = qMin(mChans, peer_chans);
+ for (int n=0; n<N; ++n) {
+ for (int c=0; c<C; ++c) {
+ memcpy(dst + (n*mChans + c)*mSmplSize, src + (n + c*N)*mSmplSize, mSmplSize);
+ }
+ }
+ src = dst;
+ }
+ if (!mJackTrip->writeAudioBuffer(src, host_buf_size, gap_size)) {
+ emit signalError("Local and Peer buffer settings are incompatible");
+ cout << "ERROR: Local and Peer buffer settings are incompatible" << endl;
+ mStopped = true;
+ break;
+ }
+ gap_size = 0;
}
}
@@ -716,12 +826,39 @@ bool UdpDataProtocol::getStats(DataProtocol::PktStat* stat)
}
//*******************************************************************************
+void UdpDataProtocol::setIssueSimulation(double loss, double jitter, double max_delay)
+{
+ mSimulatedLossRate = loss;
+ mSimulatedJitterRate = jitter;
+ mSimulatedJitterMaxDelay = max_delay;
+
+ std::random_device r;
+ mRndEngine = std::default_random_engine(r());
+ mUniformDist = std::uniform_real_distribution<double>(0.0, 1.0);
+
+ cout << "Simulating network issues: "
+ "loss_rate=" << loss << ", jitter_rate=" << jitter << ", jitter_max_delay=" << max_delay << endl;
+}
+
+//*******************************************************************************
void UdpDataProtocol::sendPacketRedundancy(int8_t* full_redundant_packet,
int full_redundant_packet_size,
int full_packet_size)
{
mJackTrip->readAudioBuffer( mAudioPacket );
- mJackTrip->putHeaderInPacket(mFullPacket, mAudioPacket);
+ int8_t* src = mAudioPacket;
+ if (1 != mChans) {
+ // Convert internal interleaved layout to non-interleaved
+ int N = getAudioPacketSizeInBites() / mChans / mSmplSize;
+ int8_t* dst = mBuffer.data();
+ for (int n=0; n<N; ++n) {
+ for (int c=0; c<mChans; ++c) {
+ memcpy(dst + (n + c*N)*mSmplSize, src + (n*mChans + c)*mSmplSize, mSmplSize);
+ }
+ }
+ src = dst;
+ }
+ mJackTrip->putHeaderInPacket(mFullPacket, src);
// Move older packets to end of array of redundant packets
std::memmove(full_redundant_packet+full_packet_size,
@@ -784,3 +921,32 @@ void UdpDataProtocol::sendPacketRedundancy(int8_t* full_redundant_packet,
If it has more than one packet that it hasn't yet received, it sends it to the soundcard
one by one.
*/
+
+bool UdpDataProtocol::datagramAvailable()
+{
+ //Currently using a simplified version of the way QUdpSocket checks for datagrams.
+ //TODO: Consider changing to use poll() or select().
+ char c;
+#if defined (__WIN_32__)
+ //Need to use the winsock version of the function for MSG_PEEK
+ WSABUF buffer;
+ buffer.buf = &c;
+ buffer.len = sizeof(c);
+ DWORD n = 0;
+ DWORD flags = MSG_PEEK;
+ int ret = WSARecv(mSocket, &buffer, 1, &n, &flags, NULL, NULL);
+ if (ret == 0) {
+ //True if no error,
+ return true;
+ } else {
+ //or if our error is that our buffer is too small.
+ int err = WSAGetLastError();
+ return (err == WSAEMSGSIZE);
+ }
+#else
+ ssize_t n;
+ n = ::recv(mSocket, &c, sizeof(c), MSG_PEEK);
+ //We have a datagram if our buffer is too small or if no error.
+ return (n != -1 || errno == EMSGSIZE);
+#endif
+}
diff --git a/src/UdpDataProtocol.h b/src/UdpDataProtocol.h
index 13d58f9..f6f570c 100644
--- a/src/UdpDataProtocol.h
+++ b/src/UdpDataProtocol.h
@@ -41,9 +41,10 @@
#include <stdexcept>
#include <QThread>
-#include <QUdpSocket>
#include <QHostAddress>
#include <QMutex>
+#include <vector>
+#include <random>
#include "DataProtocol.h"
#include "jacktrip_types.h"
@@ -104,7 +105,7 @@ public:
* \return number of bytes read, -1 on error
*/
//virtual int receivePacket(char* buf, const size_t n);
- virtual int receivePacket(QUdpSocket& UdpSocket, char* buf, const size_t n);
+ virtual int receivePacket(char* buf, const size_t n);
/** \brief Sends a packet
*
@@ -121,8 +122,7 @@ public:
* \param peerHostAddress QHostAddress to store the peer address
* \param port Receiving port
*/
- virtual void getPeerAddressFromFirstPacket(QUdpSocket& UdpSocket,
- QHostAddress& peerHostAddress,
+ virtual void getPeerAddressFromFirstPacket(QHostAddress& peerHostAddress,
uint16_t& port);
/** \brief Sets the bind port number
@@ -143,17 +143,18 @@ public:
virtual void run();
virtual bool getStats(PktStat* stat);
+ virtual void setIssueSimulation(double loss, double jitter, double max_delay);
private slots:
void printUdpWaitedTooLong(int wait_msec);
-
+
signals:
/// \brief Signals when waiting every 10 milliseconds, with the total wait on wait_msec
/// \param wait_msec Total wait in milliseconds
void signalWaitingTooLong(int wait_msec);
-
+ void signalUdpWaitingTooLong();
//private:
protected:
@@ -167,7 +168,7 @@ protected:
#endif
/** \brief This function blocks until data is available for reading in the
- * QUdpSocket. The function will timeout after timeout_msec microseconds.
+ * socket. The function will timeout after timeout_msec microseconds.
*
* This function is intended to replace QAbstractSocket::waitForReadyRead which has
* some problems with multithreading.
@@ -175,12 +176,11 @@ protected:
* \return returns true if there is data available for reading;
* otherwise it returns false (if an error occurred or the operation timed out)
*/
- void waitForReady(QUdpSocket& UdpSocket, int timeout_msec);
+ void waitForReady(int timeout_msec);
/** \brief Redundancy algorythm at the receiving end
*/
- virtual void receivePacketRedundancy(QUdpSocket& UdpSocket,
- int8_t* full_redundant_packet,
+ virtual void receivePacketRedundancy(int8_t* full_redundant_packet,
int full_redundant_packet_size,
int full_packet_size,
uint16_t& current_seq_num,
@@ -193,9 +193,9 @@ protected:
int full_redundant_packet_size,
int full_packet_size);
-
private:
-
+ bool datagramAvailable();
+
int mBindPort; ///< Local Port number to Bind
int mPeerPort; ///< Peer Port number
const runModeT mRunMode; ///< Run mode, either SENDER or RECEIVER
@@ -212,6 +212,11 @@ private:
int8_t* mAudioPacket; ///< Buffer to store Audio Packets
int8_t* mFullPacket; ///< Buffer to store Full Packet (audio+header)
+ std::vector<int8_t> mBuffer;
+ int mChans;
+ int mSmplSize;
+ int mLastOutOfOrderCount;
+ bool mInitialState;
unsigned int mUdpRedundancyFactor; ///< Factor of redundancy
static QMutex sUdpMutex; ///< Mutex to make thread safe the binding process
@@ -221,6 +226,16 @@ private:
std::atomic<uint32_t> mOutOfOrderCount;
std::atomic<uint32_t> mRevivedCount;
uint32_t mStatCount;
+
+ uint8_t mControlPacketSize;
+ bool mStopSignalSent;
+
+ // packet loss/jitter simulation
+ double mSimulatedLossRate;
+ double mSimulatedJitterRate;
+ double mSimulatedJitterMaxDelay;
+ std::default_random_engine mRndEngine;
+ std::uniform_real_distribution<double> mUniformDist;
};
#endif // __UDPDATAPROTOCOL_H__
diff --git a/src/UdpHubListener.cpp b/src/UdpHubListener.cpp
index 4cbd649..ec1b508 100644
--- a/src/UdpHubListener.cpp
+++ b/src/UdpHubListener.cpp
@@ -51,10 +51,12 @@
using std::cout; using std::endl;
+bool UdpHubListener::sSigInt = false;
//*******************************************************************************
UdpHubListener::UdpHubListener(int server_port, int server_udp_port) :
//mJTWorker(NULL),
+ mTcpServer(this),
mServerPort(server_port),
mServerUdpPort(server_udp_port),//final udp base port number
mStopped(false),
@@ -62,9 +64,12 @@ UdpHubListener::UdpHubListener(int server_port, int server_udp_port) :
mWAIR(false),
#endif // endwhere
mTotalRunningThreads(0),
- m_connectDefaultAudioPorts(false)
+ mHubPatchDescriptions({"server-to-clients", "client loopback", "client fan out/in but not loopback",
+ "reserved for TUB", "full mix", "no auto patching"}),
+ m_connectDefaultAudioPorts(false),
+ mIOStatTimeout(0)
{
- // Register JackTripWorker with the master listener
+ // Register JackTripWorker with the hub listener
//mJTWorker = new JackTripWorker(this);
mJTWorkers = new QVector<JackTripWorker*>;
for (int i = 0; i<gMaxThreads; i++) {
@@ -88,7 +93,7 @@ UdpHubListener::UdpHubListener(int server_port, int server_udp_port) :
// SoundWIRE ports open are UDP 61002-62000
// (server_port - gDefaultPort) apply TCP offset to UDP too
- if (mServerUdpPort != NULL){
+ if (mServerUdpPort != 0){
mBasePort = mServerUdpPort;
} else {
mBasePort = 61002 + (server_port - gDefaultPort);
@@ -98,6 +103,14 @@ UdpHubListener::UdpHubListener(int server_port, int server_udp_port) :
mUnderRunMode = JackTrip::WAVETABLE;
mBufferQueueLength = gDefaultQueueLength;
+
+ mBufferStrategy = 1;
+ mBroadcastQueue = 0;
+ mSimulatedLossRate = 0.0;
+ mSimulatedJitterRate = 0.0;
+ mSimulatedDelayRel = 0.0;
+
+ mUseRtUdpPriority = false;
}
@@ -119,149 +132,161 @@ UdpHubListener::~UdpHubListener()
// the client is already on the thread pool, it means that a new connection is
// requested (the old was desconnected). So we have to remove that thread from
// the pool and then connect again.
-void UdpHubListener::run()
+void UdpHubListener::start()
{
mStopped = false;
- QHostAddress PeerAddress; // Object to store peer address
- uint16_t peer_udp_port; // Peer listening port
- int server_udp_port; // Server assigned udp port
-
- // Create and bind the TCP server
+ // Bind the TCP server
// ------------------------------
- QTcpServer TcpServer;
- if ( !TcpServer.listen(QHostAddress::Any, mServerPort) ) {
- std::cerr << "TCP Socket Server ERROR on Port " << mServerPort << ": " << TcpServer.errorString().toStdString() << endl;
- std::exit(1);
+ QObject::connect(&mTcpServer, &QTcpServer::newConnection, this, &UdpHubListener::receivedNewConnection);
+ if ( !mTcpServer.listen(QHostAddress::Any, mServerPort) ) {
+ QString error_message = QString("TCP Socket Server on Port %1 ERROR: %2").arg(mServerPort).arg(mTcpServer.errorString());
+ std::cerr << error_message.toStdString() << endl;
+ emit signalError(error_message);
+ return;
}
+
+ cout << "JackTrip HUB SERVER: Waiting for client connections..." << endl;
+ cout << "JackTrip HUB SERVER: Hub auto audio patch setting = " << mHubPatch
+ << " (" << mHubPatchDescriptions.at(mHubPatch).toStdString() << ")" << endl;
+ cout << "=======================================================" << endl;
+
+ // Start our monitoring timer
+ mStopCheckTimer.setInterval(200);
+ connect(&mStopCheckTimer, &QTimer::timeout, this, &UdpHubListener::stopCheck);
+ mStopCheckTimer.start();
+}
+
+void UdpHubListener::receivedNewConnection()
+{
+ QTcpSocket *clientSocket = mTcpServer.nextPendingConnection();
+ connect(clientSocket, &QAbstractSocket::readyRead, this, [=]{
+ receivedClientInfo(clientSocket);
+ });
+ cout << "JackTrip HUB SERVER: Client Connection Received!" << endl;
+}
- const int tcpTimeout = 5*1000;
-
-
- cout << "JackTrip HUB SERVER: TCP Server Listening in Port = " << TcpServer.serverPort() << endl;
- while ( !mStopped )
- {
- cout << "JackTrip HUB SERVER: Waiting for client connections..." << endl;
- if(m_connectDefaultAudioPorts)
- {
- cout << "JackTrip HUB SERVER: Hub auto audio patch setting = " << mHubPatch << endl;
- } else {
- cout << "JackTrip HUB SERVER: Hub auto audio patch disabled " << endl;
+void UdpHubListener::receivedClientInfo(QTcpSocket *clientConnection)
+{
+ QHostAddress PeerAddress = clientConnection->peerAddress();
+ cout << "JackTrip HUB SERVER: Client Connect Received from Address : "
+ << PeerAddress.toString().toStdString() << endl;
+
+ // Get UDP port from client
+ // ------------------------
+ QString clientName = QString();
+ cout << "JackTrip HUB SERVER: Reading UDP port from Client..." << endl;
+ if (clientConnection->bytesAvailable() < (qint64)sizeof(uint16_t)) {
+ // We don't have enough data. Wait for the next readyRead notification.
+ return;
+ }
+ uint16_t peer_udp_port= readClientUdpPort(clientConnection, clientName);
+
+ cout << "JackTrip HUB SERVER: Client UDP Port is = " << peer_udp_port << endl;
+ if ( peer_udp_port == 0 || peer_udp_port < gBindPortLow || peer_udp_port > gBindPortHigh ) {
+ cout << "JackTrip HUB SERVER: Exiting " << endl;
+ clientConnection->close();
+ clientConnection->deleteLater();
+ return;
+ }
+
+ // Check is client is new or not
+ // -----------------------------
+ // Check if Address is not already in the thread pool
+ // check by comparing address strings (To handle IPv4 and IPv6.)
+ int id = isNewAddress(PeerAddress.toString(), peer_udp_port);
+ // If the address is not new, we need to remove the client from the pool
+ // before re-starting the connection
+
+ if (id == -1) {
+ int id_remove;
+ id_remove = getPoolID(PeerAddress.toString(), peer_udp_port);
+ // stop the thread
+ mJTWorkers->at(id_remove)->stopThread();
+ // block until the thread has been removed from the pool
+ while ( isNewAddress(PeerAddress.toString(), peer_udp_port) == -1 ) {
+ cout << "JackTrip HUB SERVER: Removing JackTripWorker from pool..." << endl;
+ QThread::msleep(10);
}
- cout << "=======================================================" << endl;
- while ( !TcpServer.hasPendingConnections() && !TcpServer.waitForNewConnection(1000) )
- { if (mStopped) { return; } } // block until a new connection is received
- cout << "JackTrip HUB SERVER: Client Connection Received!" << endl;
-
- // Control loop to be able to exit if UDPs or TCPs error ocurr
- for (int dum = 0; dum<1; dum++) {
- QTcpSocket *clientConnection = TcpServer.nextPendingConnection();
- if ( !clientConnection->waitForConnected(tcpTimeout) ) {
- std::cerr << clientConnection->errorString().toStdString() << endl;
- break;
- }
- PeerAddress = clientConnection->peerAddress();
- cout << "JackTrip HUB SERVER: Client Connect Received from Address : "
- << PeerAddress.toString().toStdString() << endl;
-
- // Get UDP port from client
- // ------------------------
- peer_udp_port = readClientUdpPort(clientConnection);
- if ( peer_udp_port == 0 ) {
- cout << "JackTrip HUB SERVER: Client UDP Port is = " << peer_udp_port << endl;
- cout << "JackTrip HUB SERVER: Exiting " << endl;
- break;
- }
- if ( peer_udp_port < gBindPortLow ) {
- cout << "JackTrip HUB SERVER: Client UDP Port is = " << peer_udp_port << endl;
- cout << "JackTrip HUB SERVER: Exiting " << endl;
- break;
- }
- if ( peer_udp_port > gBindPortHigh ) {
- cout << "JackTrip HUB SERVER: Client UDP Port is = " << peer_udp_port << endl;
- cout << "JackTrip HUB SERVER: Exiting " << endl;
- break;
- }
- cout << "JackTrip HUB SERVER: Client UDP Port is = " << peer_udp_port << endl;
-
- // Check is client is new or not
- // -----------------------------
- // Check if Address is not already in the thread pool
- // check by comparing address strings (To handle IPv4 and IPv6.)
- int id = isNewAddress(PeerAddress.toString(), peer_udp_port);
- // If the address is not new, we need to remove the client from the pool
- // before re-starting the connection
-
- if (id == -1) {
- int id_remove;
- id_remove = getPoolID(PeerAddress.toString(), peer_udp_port);
- // stop the thread
- mJTWorkers->at(id_remove)->stopThread();
- // block until the thread has been removed from the pool
- while ( isNewAddress(PeerAddress.toString(), peer_udp_port) == -1 ) {
- cout << "JackTrip HUB SERVER: Removing JackTripWorker from pool..." << endl;
- QThread::msleep(10);
- }
- // Get a new ID for this client
- //id = isNewAddress(PeerAddress.toIPv4Address(), peer_udp_port);
- id = getPoolID(PeerAddress.toString(), peer_udp_port);
- }
- // Assign server port and send it to Client
- server_udp_port = mBasePort+id;
- cout << "JackTrip HUB SERVER: Sending Final UDP Port to Client: " << server_udp_port << endl;
-
- if ( sendUdpPort(clientConnection, server_udp_port) == 0 ) {
- clientConnection->close();
- delete clientConnection;
- releaseThread(id);
- break;
- }
-
- // Close and Delete the socket
- // ---------------------------
- clientConnection->close();
- delete clientConnection;
- cout << "JackTrip HUB SERVER: Client TCP Connection Closed!" << endl;
-
- // Spawn Thread to Pool
- // --------------------
- // Register JackTripWorker with the master listener
- delete mJTWorkers->at(id); // just in case the Worker was previously created
- mJTWorkers->replace(id, new JackTripWorker(this, mBufferQueueLength, mUnderRunMode));
- // redirect port and spawn listener
- cout << "JackTrip HUB SERVER: Spawning JackTripWorker..." << endl;
- {
- QMutexLocker lock(&mMutex);
- mJTWorkers->at(id)->setJackTrip(id,
- mActiveAddress[id].address,
- server_udp_port,
- mActiveAddress[id].port,
- 1,
- m_connectDefaultAudioPorts
- ); /// \todo temp default to 1 channel
-
-// qDebug() << "mPeerAddress" << id << mActiveAddress[id].address << mActiveAddress[id].port;
- }
- //send one thread to the pool
- cout << "JackTrip HUB SERVER: Starting JackTripWorker..." << endl;
- mThreadPool.start(mJTWorkers->at(id), QThread::TimeCriticalPriority);
- // wait until one is complete before another spawns
- while (mJTWorkers->at(id)->isSpawning()) { QThread::msleep(10); }
- //mTotalRunningThreads++;
- cout << "JackTrip HUB SERVER: Total Running Threads: " << mTotalRunningThreads << endl;
- cout << "===============================================================" << endl;
- QThread::msleep(100);
+ // Get a new ID for this client
+ //id = isNewAddress(PeerAddress.toIPv4Address(), peer_udp_port);
+ id = getPoolID(PeerAddress.toString(), peer_udp_port);
+ }
+ // Assign server port and send it to Client
+ int server_udp_port = mBasePort+id;
+ cout << "JackTrip HUB SERVER: Sending Final UDP Port to Client: " << server_udp_port << endl;
+
+ if ( sendUdpPort(clientConnection, server_udp_port) == 0 ) {
+ clientConnection->close();
+ clientConnection->deleteLater();
+ releaseThread(id);
+ return;
+ }
+
+ // Close and mark socket for deletion
+ // ----------------------------------
+ clientConnection->close();
+ clientConnection->deleteLater();
+ cout << "JackTrip HUB SERVER: Client TCP Connection Closed!" << endl;
+
+ // Spawn Thread to Pool
+ // --------------------
+ // Register JackTripWorker with the hub listener
+ delete mJTWorkers->at(id); // just in case the Worker was previously created
+ mJTWorkers->replace(id, new JackTripWorker(this, mBufferQueueLength, mUnderRunMode, clientName));
+ if (mIOStatTimeout > 0) {
+ mJTWorkers->at(id)->setIOStatTimeout(mIOStatTimeout);
+ mJTWorkers->at(id)->setIOStatStream(mIOStatStream);
+ }
+ mJTWorkers->at(id)->setBufferStrategy(mBufferStrategy);
+ mJTWorkers->at(id)->setNetIssuesSimulation(mSimulatedLossRate,
+ mSimulatedJitterRate, mSimulatedDelayRel);
+ mJTWorkers->at(id)->setBroadcast(mBroadcastQueue);
+ mJTWorkers->at(id)->setUseRtUdpPriority(mUseRtUdpPriority);
+ // redirect port and spawn listener
+ cout << "JackTrip HUB SERVER: Spawning JackTripWorker..." << endl;
+ {
+ QMutexLocker lock(&mMutex);
+ mJTWorkers->at(id)->setJackTrip(id,
+ mActiveAddress[id].address,
+ server_udp_port,
+ mActiveAddress[id].port,
+ 1,
+ m_connectDefaultAudioPorts
+ ); /// \todo temp default to 1 channel
+
+ //qDebug() << "mPeerAddress" << id << mActiveAddress[id].address << mActiveAddress[id].port;
+ }
+ //send one thread to the pool
+ cout << "JackTrip HUB SERVER: Starting JackTripWorker..." << endl;
+ mThreadPool.start(mJTWorkers->at(id), QThread::TimeCriticalPriority);
+ // wait until one is complete before another spawns
+ while (mJTWorkers->at(id)->isSpawning()) { QThread::msleep(10); }
+ //mTotalRunningThreads++;
+ cout << "JackTrip HUB SERVER: Total Running Threads: " << mTotalRunningThreads << endl;
+ cout << "===============================================================" << endl;
+ QThread::msleep(100);
#ifdef WAIR // WAIR
- if (isWAIR()) connectMesh(true); // invoked with -Sw
+ if (isWAIR()) connectMesh(true); // invoked with -Sw
#endif // endwhere
-// qDebug() << "mPeerAddress" << mActiveAddress[id].address << mActiveAddress[id].port;
+ //qDebug() << "mPeerAddress" << mActiveAddress[id].address << mActiveAddress[id].port;
- connectPatch(true);
- }
+ connectPatch(true);
+}
+
+void UdpHubListener::stopCheck()
+{
+ if (mStopped || sSigInt) {
+ cout << "JackTrip HUB SERVER: Stopped" << endl;
+ mStopCheckTimer.stop();
+ mTcpServer.close();
+ stopAllThreads();
+ emit signalStopped();
}
+}
- /*
+ /* From Old Runloop code
// Create objects on the stack
QUdpSocket HubUdpSocket;
QHostAddress PeerAddress;
@@ -310,32 +335,26 @@ void UdpHubListener::run()
QThread::msleep(100);
}
*/
-}
-
//*******************************************************************************
// Returns 0 on error
-uint16_t UdpHubListener::readClientUdpPort(QTcpSocket* clientConnection)
+uint16_t UdpHubListener::readClientUdpPort(QTcpSocket* clientConnection, QString &clientName)
{
- // Read the size of the package
- // ----------------------------
- //tcpClient.waitForReadyRead();
- cout << "JackTrip HUB SERVER: Reading UDP port from Client..." << endl;
- while (clientConnection->bytesAvailable() < (qint64)sizeof(uint16_t)) {
- if (!clientConnection->waitForReadyRead()) {
- std::cerr << "TCP Socket ERROR: " << clientConnection->errorString().toStdString() << endl;
- return 0;
- }
- }
-
if (gVerboseFlag) cout << "Ready To Read From Client!" << endl;
// Read UDP Port Number from Server
// --------------------------------
- uint16_t udp_port = 0;
+ uint16_t udp_port;
qint64 size = sizeof(udp_port);
char port_buf[size];
clientConnection->read(port_buf, size);
std::memcpy(&udp_port, port_buf, size);
+
+ if (clientConnection->bytesAvailable() == gMaxRemoteNameLength) {
+ char name_buf[gMaxRemoteNameLength];
+ clientConnection->read(name_buf, gMaxRemoteNameLength);
+ clientName = QString::fromUtf8((const char *)name_buf);
+ }
+
return udp_port;
}
@@ -357,7 +376,7 @@ int UdpHubListener::sendUdpPort(QTcpSocket* clientConnection, int udp_port)
}
}
return 1;
- cout << "Port sent to Client" << endl;
+ //cout << "Port sent to Client" << endl;
}
@@ -489,11 +508,12 @@ void UdpHubListener::enumerateRunningThreadIDs()
#include "JMess.h"
void UdpHubListener::connectPatch(bool spawn)
{
- if(m_connectDefaultAudioPorts) {
- cout << ((spawn)?"spawning":"releasing") << " jacktripWorker so change patch" << endl;
- } else {
- cout << ((spawn)?"spawning":"releasing") << " jacktripWorker" << endl;
+ if ((getHubPatch() == JackTrip::NOAUTO) ||
+ (getHubPatch() == JackTrip::SERVERTOCLIENT && !m_connectDefaultAudioPorts)) {
+ cout << ((spawn)?"spawning":"releasing") << " jacktripWorker (auto hub patching disabled)" << endl;
+ return;
}
+ cout << ((spawn)?"spawning":"releasing") << " jacktripWorker so change patch" << endl;
JMess tmp;
// default is patch 0, which connects server audio to all clients
// these are the other cases:
@@ -506,5 +526,17 @@ void UdpHubListener::connectPatch(bool spawn)
// FIXME: need change to gDefaultNumInChannels if more than stereo
}
+void UdpHubListener::stopAllThreads()
+{
+ QVectorIterator<JackTripWorker*> iterator(*mJTWorkers);
+ while (iterator.hasNext()) {
+ if (iterator.peekNext() != nullptr) {
+ iterator.next()->stopThread();
+ } else {
+ iterator.next();
+ }
+ }
+ mThreadPool.waitForDone();
+}
// TODO:
// USE bool QAbstractSocket::isValid () const to check if socket is connect. if not, exit loop
diff --git a/src/UdpHubListener.h b/src/UdpHubListener.h
index 0bc0a8c..763cfea 100644
--- a/src/UdpHubListener.h
+++ b/src/UdpHubListener.h
@@ -40,6 +40,7 @@
#include <iostream>
#include <stdexcept>
+#include <fstream>
#include <QThread>
#include <QThreadPool>
@@ -65,17 +66,16 @@ typedef struct {
* This creates a server that will listen on the well know port (the server port) and will
* spawn JackTrip threads into the Thread pool. Clients request a connection.
*/
-class UdpHubListener : public QThread
+class UdpHubListener : public QObject
{
Q_OBJECT;
public:
- UdpHubListener(int server_port = gServerUdpPort, int server_udp_port = NULL);
+ UdpHubListener(int server_port = gServerUdpPort, int server_udp_port = 0);
virtual ~UdpHubListener();
- /// \brief Implements the Thread Loop. To start the thread, call start()
- /// ( DO NOT CALL run() )
- void run();
+ /// \brief Starts the TCP server
+ void start();
/// \brief Stops the execution of the Thread
void stop() { mStopped = true; }
@@ -83,28 +83,33 @@ public:
int releaseThread(int id);
void setConnectDefaultAudioPorts(bool connectDefaultAudioPorts) { m_connectDefaultAudioPorts = connectDefaultAudioPorts; }
-
- void setSettings(Settings* s) {m_settings = s;}
- Settings* getSettings() const {return m_settings;}
+
+ static void sigIntHandler(__attribute__((unused)) int unused)
+ { std::cout << std::endl << "Shutting Down..." << std::endl; sSigInt = true; }
private slots:
void testReceive()
{ std::cout << "========= TEST RECEIVE SLOT ===========" << std::endl; }
+ void receivedNewConnection();
+ void stopCheck();
signals:
void Listening();
void ClientAddressSet();
void signalRemoveThread(int id);
-
+ void signalStopped();
+ void signalError(const QString &errorMessage);
private:
/** \brief Binds a QUdpSocket. It chooses the available (active) interface.
* \param udpsocket a QUdpSocket
* \param port Port number
*/
+ void receivedClientInfo(QTcpSocket *clientConnection);
+
static void bindUdpSocket(QUdpSocket& udpsocket, int port);
- uint16_t readClientUdpPort(QTcpSocket* clientConnection);
+ uint16_t readClientUdpPort(QTcpSocket* clientConnection, QString &clientName);
int sendUdpPort(QTcpSocket* clientConnection, int udp_port);
@@ -124,6 +129,8 @@ private:
* is not in the pool yet, returns -1.
*/
int getPoolID(QString address, uint16_t port);
+
+ void stopAllThreads();
//QUdpSocket mUdpHubSocket; ///< The UDP socket
//QHostAddress mPeerAddress; ///< The Peer Address
@@ -132,6 +139,7 @@ private:
QVector<JackTripWorker*>* mJTWorkers; ///< Vector of JackTripWorker s
QThreadPool mThreadPool; ///< The Thread Pool
+ QTcpServer mTcpServer;
int mServerPort; //< Server known port number
int mServerUdpPort; //< Server udp base port number
int mBasePort;
@@ -140,14 +148,26 @@ private:
/// Boolean stop the execution of the thread
volatile bool mStopped;
+ static bool sSigInt;
+ QTimer mStopCheckTimer;
int mTotalRunningThreads; ///< Number of Threads running in the pool
QMutex mMutex;
JackTrip::underrunModeT mUnderRunMode;
int mBufferQueueLength;
-
+
+ QStringList mHubPatchDescriptions;
bool m_connectDefaultAudioPorts;
- Settings* m_settings;
+ int mIOStatTimeout;
+ QSharedPointer<std::ofstream> mIOStatStream;
+
+ int mBufferStrategy;
+ int mBroadcastQueue;
+ double mSimulatedLossRate;
+ double mSimulatedJitterRate;
+ double mSimulatedDelayRel;
+ bool mUseRtUdpPriority;
+
#ifdef WAIR // wair
bool mWAIR;
void connectMesh(bool spawn);
@@ -164,6 +184,20 @@ public :
void setUnderRunMode(JackTrip::underrunModeT UnderRunMode) { mUnderRunMode = UnderRunMode; }
void setBufferQueueLength(int BufferQueueLength) { mBufferQueueLength = BufferQueueLength; }
+
+ void setIOStatTimeout(int timeout) { mIOStatTimeout = timeout; }
+ void setIOStatStream(QSharedPointer<std::ofstream> statStream) { mIOStatStream = statStream; }
+
+ void setBufferStrategy(int BufferStrategy) { mBufferStrategy = BufferStrategy; }
+ void setNetIssuesSimulation(double loss, double jitter, double delay_rel)
+ {
+ mSimulatedLossRate = loss;
+ mSimulatedJitterRate = jitter;
+ mSimulatedDelayRel = delay_rel;
+ }
+ void setBroadcast(int broadcast_queue) {mBroadcastQueue = broadcast_queue;}
+ void setUseRtUdpPriority(bool use) {mUseRtUdpPriority = use;}
+
};
diff --git a/src/build b/src/build
index e3f7150..65ce621 100755
--- a/src/build
+++ b/src/build
@@ -37,8 +37,8 @@ if [[ $1 == 'nojack' ]]; then
$QCMD -spec $QSPEC -config nojack ../src/jacktrip.pro
make release
else
- $QCMD -spec $QSPEC ../src/jacktrip.pro
+ $QCMD -spec $QSPEC ../src/jacktrip.pro $@
make clean
- $QCMD -spec $QSPEC ../src/jacktrip.pro
+ $QCMD -spec $QSPEC ../src/jacktrip.pro $@
make release
fi
diff --git a/src/compressordsp.h b/src/compressordsp.h
new file mode 100644
index 0000000..26b37ac
--- /dev/null
+++ b/src/compressordsp.h
@@ -0,0 +1,1816 @@
+/* ------------------------------------------------------------
+author: "Julius Smith"
+license: "MIT Style STK-4.2"
+name: "compressor"
+version: "0.0"
+Code generated with Faust 2.28.6 (https://faust.grame.fr)
+Compilation options: -lang cpp -inpl -scal -ftz 0
+------------------------------------------------------------ */
+
+#ifndef __compressordsp_H__
+#define __compressordsp_H__
+
+// NOTE: ANY INCLUDE-GUARD HERE MUST BE DERIVED FROM THE CLASS NAME
+//
+// faust2header.cpp - FAUST Architecture File
+// This is a simple variation of matlabplot.cpp in the Faust distribution
+// aimed at creating a simple C++ header file (.h) containing a Faust DSP.
+// See the Makefile for how to use it.
+
+/************************** BEGIN dsp.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __dsp__
+#define __dsp__
+
+#include <string>
+#include <vector>
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+struct UI;
+struct Meta;
+
+/**
+ * DSP memory manager.
+ */
+
+struct dsp_memory_manager {
+
+ virtual ~dsp_memory_manager() {}
+
+ virtual void* allocate(size_t size) = 0;
+ virtual void destroy(void* ptr) = 0;
+
+};
+
+/**
+* Signal processor definition.
+*/
+
+class dsp {
+
+ public:
+
+ dsp() {}
+ virtual ~dsp() {}
+
+ /* Return instance number of audio inputs */
+ virtual int getNumInputs() = 0;
+
+ /* Return instance number of audio outputs */
+ virtual int getNumOutputs() = 0;
+
+ /**
+ * Trigger the ui_interface parameter with instance specific calls
+ * to 'openTabBox', 'addButton', 'addVerticalSlider'... in order to build the UI.
+ *
+ * @param ui_interface - the user interface builder
+ */
+ virtual void buildUserInterface(UI* ui_interface) = 0;
+
+ /* Returns the sample rate currently used by the instance */
+ virtual int getSampleRate() = 0;
+
+ /**
+ * Global init, calls the following methods:
+ * - static class 'classInit': static tables initialization
+ * - 'instanceInit': constants and instance state initialization
+ *
+ * @param sample_rate - the sampling rate in Hertz
+ */
+ virtual void init(int sample_rate) = 0;
+
+ /**
+ * Init instance state
+ *
+ * @param sample_rate - the sampling rate in Hertz
+ */
+ virtual void instanceInit(int sample_rate) = 0;
+
+ /**
+ * Init instance constant state
+ *
+ * @param sample_rate - the sampling rate in Hertz
+ */
+ virtual void instanceConstants(int sample_rate) = 0;
+
+ /* Init default control parameters values */
+ virtual void instanceResetUserInterface() = 0;
+
+ /* Init instance state (delay lines...) */
+ virtual void instanceClear() = 0;
+
+ /**
+ * Return a clone of the instance.
+ *
+ * @return a copy of the instance on success, otherwise a null pointer.
+ */
+ virtual dsp* clone() = 0;
+
+ /**
+ * Trigger the Meta* parameter with instance specific calls to 'declare' (key, value) metadata.
+ *
+ * @param m - the Meta* meta user
+ */
+ virtual void metadata(Meta* m) = 0;
+
+ /**
+ * DSP instance computation, to be called with successive in/out audio buffers.
+ *
+ * @param count - the number of frames to compute
+ * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
+ * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
+ *
+ */
+ virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) = 0;
+
+ /**
+ * DSP instance computation: alternative method to be used by subclasses.
+ *
+ * @param date_usec - the timestamp in microsec given by audio driver.
+ * @param count - the number of frames to compute
+ * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
+ * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
+ *
+ */
+ virtual void compute(double /*date_usec*/, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { compute(count, inputs, outputs); }
+
+};
+
+/**
+ * Generic DSP decorator.
+ */
+
+class decorator_dsp : public dsp {
+
+ protected:
+
+ dsp* fDSP;
+
+ public:
+
+ decorator_dsp(dsp* dsp = nullptr):fDSP(dsp) {}
+ virtual ~decorator_dsp() { delete fDSP; }
+
+ virtual int getNumInputs() { return fDSP->getNumInputs(); }
+ virtual int getNumOutputs() { return fDSP->getNumOutputs(); }
+ virtual void buildUserInterface(UI* ui_interface) { fDSP->buildUserInterface(ui_interface); }
+ virtual int getSampleRate() { return fDSP->getSampleRate(); }
+ virtual void init(int sample_rate) { fDSP->init(sample_rate); }
+ virtual void instanceInit(int sample_rate) { fDSP->instanceInit(sample_rate); }
+ virtual void instanceConstants(int sample_rate) { fDSP->instanceConstants(sample_rate); }
+ virtual void instanceResetUserInterface() { fDSP->instanceResetUserInterface(); }
+ virtual void instanceClear() { fDSP->instanceClear(); }
+ virtual decorator_dsp* clone() { return new decorator_dsp(fDSP->clone()); }
+ virtual void metadata(Meta* m) { fDSP->metadata(m); }
+ // Beware: subclasses usually have to overload the two 'compute' methods
+ virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(count, inputs, outputs); }
+ virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(date_usec, count, inputs, outputs); }
+
+};
+
+/**
+ * DSP factory class.
+ */
+
+class dsp_factory {
+
+ protected:
+
+ // So that to force sub-classes to use deleteDSPFactory(dsp_factory* factory);
+ virtual ~dsp_factory() {}
+
+ public:
+
+ virtual std::string getName() = 0;
+ virtual std::string getSHAKey() = 0;
+ virtual std::string getDSPCode() = 0;
+ virtual std::string getCompileOptions() = 0;
+ virtual std::vector<std::string> getLibraryList() = 0;
+ virtual std::vector<std::string> getIncludePathnames() = 0;
+
+ virtual dsp* createDSPInstance() = 0;
+
+ virtual void setMemoryManager(dsp_memory_manager* manager) = 0;
+ virtual dsp_memory_manager* getMemoryManager() = 0;
+
+};
+
+/**
+ * On Intel set FZ (Flush to Zero) and DAZ (Denormals Are Zero)
+ * flags to avoid costly denormals.
+ */
+
+#ifdef __SSE__
+ #include <xmmintrin.h>
+ #ifdef __SSE2__
+ #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
+ #else
+ #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
+ #endif
+#else
+ #define AVOIDDENORMALS
+#endif
+
+#endif
+/************************** END dsp.h **************************/
+
+/************************** BEGIN APIUI.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef API_UI_H
+#define API_UI_H
+
+#include <sstream>
+#include <string>
+#include <vector>
+#include <iostream>
+#include <map>
+
+/************************** BEGIN meta.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __meta__
+#define __meta__
+
+struct Meta
+{
+ virtual ~Meta() {};
+ virtual void declare(const char* key, const char* value) = 0;
+
+};
+
+#endif
+/************************** END meta.h **************************/
+/************************** BEGIN UI.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2020 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __UI_H__
+#define __UI_H__
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+/*******************************************************************************
+ * UI : Faust DSP User Interface
+ * User Interface as expected by the buildUserInterface() method of a DSP.
+ * This abstract class contains only the method that the Faust compiler can
+ * generate to describe a DSP user interface.
+ ******************************************************************************/
+
+struct Soundfile;
+
+template <typename REAL>
+struct UIReal
+{
+ UIReal() {}
+ virtual ~UIReal() {}
+
+ // -- widget's layouts
+
+ virtual void openTabBox(const char* label) = 0;
+ virtual void openHorizontalBox(const char* label) = 0;
+ virtual void openVerticalBox(const char* label) = 0;
+ virtual void closeBox() = 0;
+
+ // -- active widgets
+
+ virtual void addButton(const char* label, REAL* zone) = 0;
+ virtual void addCheckButton(const char* label, REAL* zone) = 0;
+ virtual void addVerticalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
+ virtual void addHorizontalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
+ virtual void addNumEntry(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
+
+ // -- passive widgets
+
+ virtual void addHorizontalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
+ virtual void addVerticalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
+
+ // -- soundfiles
+
+ virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) = 0;
+
+ // -- metadata declarations
+
+ virtual void declare(REAL* zone, const char* key, const char* val) {}
+};
+
+struct UI : public UIReal<FAUSTFLOAT>
+{
+ UI() {}
+ virtual ~UI() {}
+};
+
+#endif
+/************************** END UI.h **************************/
+/************************** BEGIN PathBuilder.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef FAUST_PATHBUILDER_H
+#define FAUST_PATHBUILDER_H
+
+#include <vector>
+#include <string>
+#include <algorithm>
+
+/*******************************************************************************
+ * PathBuilder : Faust User Interface
+ * Helper class to build complete hierarchical path for UI items.
+ ******************************************************************************/
+
+class PathBuilder
+{
+
+ protected:
+
+ std::vector<std::string> fControlsLevel;
+
+ public:
+
+ PathBuilder() {}
+ virtual ~PathBuilder() {}
+
+ std::string buildPath(const std::string& label)
+ {
+ std::string res = "/";
+ for (size_t i = 0; i < fControlsLevel.size(); i++) {
+ res += fControlsLevel[i];
+ res += "/";
+ }
+ res += label;
+ std::replace(res.begin(), res.end(), ' ', '_');
+ return res;
+ }
+
+ std::string buildLabel(std::string label)
+ {
+ std::replace(label.begin(), label.end(), ' ', '_');
+ return label;
+ }
+
+ void pushLabel(const std::string& label) { fControlsLevel.push_back(label); }
+ void popLabel() { fControlsLevel.pop_back(); }
+
+};
+
+#endif // FAUST_PATHBUILDER_H
+/************************** END PathBuilder.h **************************/
+/************************** BEGIN ValueConverter.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __ValueConverter__
+#define __ValueConverter__
+
+/***************************************************************************************
+ ValueConverter.h
+ (GRAME, Copyright 2015-2019)
+
+Set of conversion objects used to map user interface values (for example a gui slider
+delivering values between 0 and 1) to faust values (for example a vslider between
+20 and 20000) using a log scale.
+
+-- Utilities
+
+Range(lo,hi) : clip a value x between lo and hi
+Interpolator(lo,hi,v1,v2) : Maps a value x between lo and hi to a value y between v1 and v2
+Interpolator3pt(lo,mi,hi,v1,vm,v2) : Map values between lo mid hi to values between v1 vm v2
+
+-- Value Converters
+
+ValueConverter::ui2faust(x)
+ValueConverter::faust2ui(x)
+
+-- ValueConverters used for sliders depending of the scale
+
+LinearValueConverter(umin, umax, fmin, fmax)
+LinearValueConverter2(lo, mi, hi, v1, vm, v2) using 2 segments
+LogValueConverter(umin, umax, fmin, fmax)
+ExpValueConverter(umin, umax, fmin, fmax)
+
+-- ValueConverters used for accelerometers based on 3 points
+
+AccUpConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 0
+AccDownConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 1
+AccUpDownConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 2
+AccDownUpConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 3
+
+-- lists of ZoneControl are used to implement accelerometers metadata for each axes
+
+ZoneControl(zone, valueConverter) : a zone with an accelerometer data converter
+
+-- ZoneReader are used to implement screencolor metadata
+
+ZoneReader(zone, valueConverter) : a zone with a data converter
+
+****************************************************************************************/
+
+#include <float.h>
+#include <algorithm> // std::max
+#include <cmath>
+#include <vector>
+#include <assert.h>
+
+//--------------------------------------------------------------------------------------
+// Interpolator(lo,hi,v1,v2)
+// Maps a value x between lo and hi to a value y between v1 and v2
+// y = v1 + (x-lo)/(hi-lo)*(v2-v1)
+// y = v1 + (x-lo) * coef with coef = (v2-v1)/(hi-lo)
+// y = v1 + x*coef - lo*coef
+// y = v1 - lo*coef + x*coef
+// y = offset + x*coef with offset = v1 - lo*coef
+//--------------------------------------------------------------------------------------
+class Interpolator
+{
+ private:
+
+ //--------------------------------------------------------------------------------------
+ // Range(lo,hi) clip a value between lo and hi
+ //--------------------------------------------------------------------------------------
+ struct Range
+ {
+ double fLo;
+ double fHi;
+
+ Range(double x, double y) : fLo(std::min<double>(x,y)), fHi(std::max<double>(x,y)) {}
+ double operator()(double x) { return (x<fLo) ? fLo : (x>fHi) ? fHi : x; }
+ };
+
+
+ Range fRange;
+ double fCoef;
+ double fOffset;
+
+ public:
+
+ Interpolator(double lo, double hi, double v1, double v2) : fRange(lo,hi)
+ {
+ if (hi != lo) {
+ // regular case
+ fCoef = (v2-v1)/(hi-lo);
+ fOffset = v1 - lo*fCoef;
+ } else {
+ // degenerate case, avoids division by zero
+ fCoef = 0;
+ fOffset = (v1+v2)/2;
+ }
+ }
+ double operator()(double v)
+ {
+ double x = fRange(v);
+ return fOffset + x*fCoef;
+ }
+
+ void getLowHigh(double& amin, double& amax)
+ {
+ amin = fRange.fLo;
+ amax = fRange.fHi;
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Interpolator3pt(lo,mi,hi,v1,vm,v2)
+// Map values between lo mid hi to values between v1 vm v2
+//--------------------------------------------------------------------------------------
+class Interpolator3pt
+{
+
+ private:
+
+ Interpolator fSegment1;
+ Interpolator fSegment2;
+ double fMid;
+
+ public:
+
+ Interpolator3pt(double lo, double mi, double hi, double v1, double vm, double v2) :
+ fSegment1(lo, mi, v1, vm),
+ fSegment2(mi, hi, vm, v2),
+ fMid(mi) {}
+ double operator()(double x) { return (x < fMid) ? fSegment1(x) : fSegment2(x); }
+
+ void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fSegment1.getLowHigh(amin, amid);
+ fSegment2.getLowHigh(amid, amax);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Abstract ValueConverter class. Converts values between UI and Faust representations
+//--------------------------------------------------------------------------------------
+class ValueConverter
+{
+
+ public:
+
+ virtual ~ValueConverter() {}
+ virtual double ui2faust(double x) = 0;
+ virtual double faust2ui(double x) = 0;
+};
+
+//--------------------------------------------------------------------------------------
+// A converter than can be updated
+//--------------------------------------------------------------------------------------
+
+class UpdatableValueConverter : public ValueConverter {
+
+ protected:
+
+ bool fActive;
+
+ public:
+
+ UpdatableValueConverter():fActive(true)
+ {}
+ virtual ~UpdatableValueConverter()
+ {}
+
+ virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max) = 0;
+ virtual void getMappingValues(double& amin, double& amid, double& amax) = 0;
+
+ void setActive(bool on_off) { fActive = on_off; }
+ bool getActive() { return fActive; }
+
+};
+
+
+//--------------------------------------------------------------------------------------
+// Linear conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class LinearValueConverter : public ValueConverter
+{
+
+ private:
+
+ Interpolator fUI2F;
+ Interpolator fF2UI;
+
+ public:
+
+ LinearValueConverter(double umin, double umax, double fmin, double fmax) :
+ fUI2F(umin,umax,fmin,fmax), fF2UI(fmin,fmax,umin,umax)
+ {}
+
+ LinearValueConverter() : fUI2F(0.,0.,0.,0.), fF2UI(0.,0.,0.,0.)
+ {}
+ virtual double ui2faust(double x) { return fUI2F(x); }
+ virtual double faust2ui(double x) { return fF2UI(x); }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Two segments linear conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class LinearValueConverter2 : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fUI2F;
+ Interpolator3pt fF2UI;
+
+ public:
+
+ LinearValueConverter2(double amin, double amid, double amax, double min, double init, double max) :
+ fUI2F(amin, amid, amax, min, init, max), fF2UI(min, init, max, amin, amid, amax)
+ {}
+
+ LinearValueConverter2() : fUI2F(0.,0.,0.,0.,0.,0.), fF2UI(0.,0.,0.,0.,0.,0.)
+ {}
+
+ virtual double ui2faust(double x) { return fUI2F(x); }
+ virtual double faust2ui(double x) { return fF2UI(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max)
+ {
+ fUI2F = Interpolator3pt(amin, amid, amax, min, init, max);
+ fF2UI = Interpolator3pt(min, init, max, amin, amid, amax);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fUI2F.getMappingValues(amin, amid, amax);
+ }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Logarithmic conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class LogValueConverter : public LinearValueConverter
+{
+
+ public:
+
+ LogValueConverter(double umin, double umax, double fmin, double fmax) :
+ LinearValueConverter(umin, umax, std::log(std::max<double>(DBL_MIN, fmin)), std::log(std::max<double>(DBL_MIN, fmax)))
+ {}
+
+ virtual double ui2faust(double x) { return std::exp(LinearValueConverter::ui2faust(x)); }
+ virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::log(std::max<double>(x, DBL_MIN))); }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Exponential conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class ExpValueConverter : public LinearValueConverter
+{
+
+ public:
+
+ ExpValueConverter(double umin, double umax, double fmin, double fmax) :
+ LinearValueConverter(umin, umax, std::min<double>(DBL_MAX, std::exp(fmin)), std::min<double>(DBL_MAX, std::exp(fmax)))
+ {}
+
+ virtual double ui2faust(double x) { return std::log(LinearValueConverter::ui2faust(x)); }
+ virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::min<double>(DBL_MAX, std::exp(x))); }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using an Up curve (curve 0)
+//--------------------------------------------------------------------------------------
+class AccUpConverter : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fA2F;
+ Interpolator3pt fF2A;
+
+ public:
+
+ AccUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
+ fA2F(amin,amid,amax,fmin,fmid,fmax),
+ fF2A(fmin,fmid,fmax,amin,amid,amax)
+ {}
+
+ virtual double ui2faust(double x) { return fA2F(x); }
+ virtual double faust2ui(double x) { return fF2A(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
+ {
+ //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+ fA2F = Interpolator3pt(amin, amid, amax, fmin, fmid, fmax);
+ fF2A = Interpolator3pt(fmin, fmid, fmax, amin, amid, amax);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fA2F.getMappingValues(amin, amid, amax);
+ }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using a Down curve (curve 1)
+//--------------------------------------------------------------------------------------
+class AccDownConverter : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fA2F;
+ Interpolator3pt fF2A;
+
+ public:
+
+ AccDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
+ fA2F(amin,amid,amax,fmax,fmid,fmin),
+ fF2A(fmin,fmid,fmax,amax,amid,amin)
+ {}
+
+ virtual double ui2faust(double x) { return fA2F(x); }
+ virtual double faust2ui(double x) { return fF2A(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
+ {
+ //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+ fA2F = Interpolator3pt(amin, amid, amax, fmax, fmid, fmin);
+ fF2A = Interpolator3pt(fmin, fmid, fmax, amax, amid, amin);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fA2F.getMappingValues(amin, amid, amax);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using an Up-Down curve (curve 2)
+//--------------------------------------------------------------------------------------
+class AccUpDownConverter : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fA2F;
+ Interpolator fF2A;
+
+ public:
+
+ AccUpDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
+ fA2F(amin,amid,amax,fmin,fmax,fmin),
+ fF2A(fmin,fmax,amin,amax) // Special, pseudo inverse of a non monotonic function
+ {}
+
+ virtual double ui2faust(double x) { return fA2F(x); }
+ virtual double faust2ui(double x) { return fF2A(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
+ {
+ //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+ fA2F = Interpolator3pt(amin, amid, amax, fmin, fmax, fmin);
+ fF2A = Interpolator(fmin, fmax, amin, amax);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fA2F.getMappingValues(amin, amid, amax);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using a Down-Up curve (curve 3)
+//--------------------------------------------------------------------------------------
+class AccDownUpConverter : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fA2F;
+ Interpolator fF2A;
+
+ public:
+
+ AccDownUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
+ fA2F(amin,amid,amax,fmax,fmin,fmax),
+ fF2A(fmin,fmax,amin,amax) // Special, pseudo inverse of a non monotonic function
+ {}
+
+ virtual double ui2faust(double x) { return fA2F(x); }
+ virtual double faust2ui(double x) { return fF2A(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
+ {
+ //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+ fA2F = Interpolator3pt(amin, amid, amax, fmax, fmin, fmax);
+ fF2A = Interpolator(fmin, fmax, amin, amax);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fA2F.getMappingValues(amin, amid, amax);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Base class for ZoneControl
+//--------------------------------------------------------------------------------------
+class ZoneControl
+{
+
+ protected:
+
+ FAUSTFLOAT* fZone;
+
+ public:
+
+ ZoneControl(FAUSTFLOAT* zone) : fZone(zone) {}
+ virtual ~ZoneControl() {}
+
+ virtual void update(double v) const {}
+
+ virtual void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max) {}
+ virtual void getMappingValues(double& amin, double& amid, double& amax) {}
+
+ FAUSTFLOAT* getZone() { return fZone; }
+
+ virtual void setActive(bool on_off) {}
+ virtual bool getActive() { return false; }
+
+ virtual int getCurve() { return -1; }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Useful to implement accelerometers metadata as a list of ZoneControl for each axes
+//--------------------------------------------------------------------------------------
+class ConverterZoneControl : public ZoneControl
+{
+
+ protected:
+
+ ValueConverter* fValueConverter;
+
+ public:
+
+ ConverterZoneControl(FAUSTFLOAT* zone, ValueConverter* converter) : ZoneControl(zone), fValueConverter(converter) {}
+ virtual ~ConverterZoneControl() { delete fValueConverter; } // Assuming fValueConverter is not kept elsewhere...
+
+ virtual void update(double v) const { *fZone = fValueConverter->ui2faust(v); }
+
+ ValueConverter* getConverter() { return fValueConverter; }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Association of a zone and a four value converter, each one for each possible curve.
+// Useful to implement accelerometers metadata as a list of ZoneControl for each axes
+//--------------------------------------------------------------------------------------
+class CurveZoneControl : public ZoneControl
+{
+
+ private:
+
+ std::vector<UpdatableValueConverter*> fValueConverters;
+ int fCurve;
+
+ public:
+
+ CurveZoneControl(FAUSTFLOAT* zone, int curve, double amin, double amid, double amax, double min, double init, double max) : ZoneControl(zone), fCurve(0)
+ {
+ assert(curve >= 0 && curve <= 3);
+ fValueConverters.push_back(new AccUpConverter(amin, amid, amax, min, init, max));
+ fValueConverters.push_back(new AccDownConverter(amin, amid, amax, min, init, max));
+ fValueConverters.push_back(new AccUpDownConverter(amin, amid, amax, min, init, max));
+ fValueConverters.push_back(new AccDownUpConverter(amin, amid, amax, min, init, max));
+ fCurve = curve;
+ }
+ virtual ~CurveZoneControl()
+ {
+ std::vector<UpdatableValueConverter*>::iterator it;
+ for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
+ delete(*it);
+ }
+ }
+ void update(double v) const { if (fValueConverters[fCurve]->getActive()) *fZone = fValueConverters[fCurve]->ui2faust(v); }
+
+ void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max)
+ {
+ fValueConverters[curve]->setMappingValues(amin, amid, amax, min, init, max);
+ fCurve = curve;
+ }
+
+ void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fValueConverters[fCurve]->getMappingValues(amin, amid, amax);
+ }
+
+ void setActive(bool on_off)
+ {
+ std::vector<UpdatableValueConverter*>::iterator it;
+ for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
+ (*it)->setActive(on_off);
+ }
+ }
+
+ int getCurve() { return fCurve; }
+};
+
+class ZoneReader
+{
+
+ private:
+
+ FAUSTFLOAT* fZone;
+ Interpolator fInterpolator;
+
+ public:
+
+ ZoneReader(FAUSTFLOAT* zone, double lo, double hi) : fZone(zone), fInterpolator(lo, hi, 0, 255) {}
+
+ virtual ~ZoneReader() {}
+
+ int getValue()
+ {
+ return (fZone != nullptr) ? int(fInterpolator(*fZone)) : 127;
+ }
+
+};
+
+#endif
+/************************** END ValueConverter.h **************************/
+
+class APIUI : public PathBuilder, public Meta, public UI
+{
+ public:
+
+ enum ItemType { kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry, kHBargraph, kVBargraph };
+
+ protected:
+
+ enum { kLin = 0, kLog = 1, kExp = 2 };
+
+ int fNumParameters;
+ std::vector<std::string> fPaths;
+ std::vector<std::string> fLabels;
+ std::map<std::string, int> fPathMap;
+ std::map<std::string, int> fLabelMap;
+ std::vector<ValueConverter*> fConversion;
+ std::vector<FAUSTFLOAT*> fZone;
+ std::vector<FAUSTFLOAT> fInit;
+ std::vector<FAUSTFLOAT> fMin;
+ std::vector<FAUSTFLOAT> fMax;
+ std::vector<FAUSTFLOAT> fStep;
+ std::vector<ItemType> fItemType;
+ std::vector<std::map<std::string, std::string> > fMetaData;
+ std::vector<ZoneControl*> fAcc[3];
+ std::vector<ZoneControl*> fGyr[3];
+
+ // Screen color control
+ // "...[screencolor:red]..." etc.
+ bool fHasScreenControl; // true if control screen color metadata
+ ZoneReader* fRedReader;
+ ZoneReader* fGreenReader;
+ ZoneReader* fBlueReader;
+
+ // Current values controlled by metadata
+ std::string fCurrentUnit;
+ int fCurrentScale;
+ std::string fCurrentAcc;
+ std::string fCurrentGyr;
+ std::string fCurrentColor;
+ std::string fCurrentTooltip;
+ std::map<std::string, std::string> fCurrentMetadata;
+
+ // Add a generic parameter
+ virtual void addParameter(const char* label,
+ FAUSTFLOAT* zone,
+ FAUSTFLOAT init,
+ FAUSTFLOAT min,
+ FAUSTFLOAT max,
+ FAUSTFLOAT step,
+ ItemType type)
+ {
+ std::string path = buildPath(label);
+ fPathMap[path] = fLabelMap[label] = fNumParameters++;
+ fPaths.push_back(path);
+ fLabels.push_back(label);
+ fZone.push_back(zone);
+ fInit.push_back(init);
+ fMin.push_back(min);
+ fMax.push_back(max);
+ fStep.push_back(step);
+ fItemType.push_back(type);
+
+ // handle scale metadata
+ switch (fCurrentScale) {
+ case kLin:
+ fConversion.push_back(new LinearValueConverter(0, 1, min, max));
+ break;
+ case kLog:
+ fConversion.push_back(new LogValueConverter(0, 1, min, max));
+ break;
+ case kExp: fConversion.push_back(new ExpValueConverter(0, 1, min, max));
+ break;
+ }
+ fCurrentScale = kLin;
+
+ if (fCurrentAcc.size() > 0 && fCurrentGyr.size() > 0) {
+ std::cerr << "warning : 'acc' and 'gyr' metadata used for the same " << label << " parameter !!\n";
+ }
+
+ // handle acc metadata "...[acc : <axe> <curve> <amin> <amid> <amax>]..."
+ if (fCurrentAcc.size() > 0) {
+ std::istringstream iss(fCurrentAcc);
+ int axe, curve;
+ double amin, amid, amax;
+ iss >> axe >> curve >> amin >> amid >> amax;
+
+ if ((0 <= axe) && (axe < 3) &&
+ (0 <= curve) && (curve < 4) &&
+ (amin < amax) && (amin <= amid) && (amid <= amax))
+ {
+ fAcc[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
+ } else {
+ std::cerr << "incorrect acc metadata : " << fCurrentAcc << std::endl;
+ }
+ fCurrentAcc = "";
+ }
+
+ // handle gyr metadata "...[gyr : <axe> <curve> <amin> <amid> <amax>]..."
+ if (fCurrentGyr.size() > 0) {
+ std::istringstream iss(fCurrentGyr);
+ int axe, curve;
+ double amin, amid, amax;
+ iss >> axe >> curve >> amin >> amid >> amax;
+
+ if ((0 <= axe) && (axe < 3) &&
+ (0 <= curve) && (curve < 4) &&
+ (amin < amax) && (amin <= amid) && (amid <= amax))
+ {
+ fGyr[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
+ } else {
+ std::cerr << "incorrect gyr metadata : " << fCurrentGyr << std::endl;
+ }
+ fCurrentGyr = "";
+ }
+
+ // handle screencolor metadata "...[screencolor:red|green|blue|white]..."
+ if (fCurrentColor.size() > 0) {
+ if ((fCurrentColor == "red") && (fRedReader == 0)) {
+ fRedReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else if ((fCurrentColor == "green") && (fGreenReader == 0)) {
+ fGreenReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else if ((fCurrentColor == "blue") && (fBlueReader == 0)) {
+ fBlueReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else if ((fCurrentColor == "white") && (fRedReader == 0) && (fGreenReader == 0) && (fBlueReader == 0)) {
+ fRedReader = new ZoneReader(zone, min, max);
+ fGreenReader = new ZoneReader(zone, min, max);
+ fBlueReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else {
+ std::cerr << "incorrect screencolor metadata : " << fCurrentColor << std::endl;
+ }
+ }
+ fCurrentColor = "";
+
+ fMetaData.push_back(fCurrentMetadata);
+ fCurrentMetadata.clear();
+ }
+
+ int getZoneIndex(std::vector<ZoneControl*>* table, int p, int val)
+ {
+ FAUSTFLOAT* zone = fZone[p];
+ for (size_t i = 0; i < table[val].size(); i++) {
+ if (zone == table[val][i]->getZone()) return int(i);
+ }
+ return -1;
+ }
+
+ void setConverter(std::vector<ZoneControl*>* table, int p, int val, int curve, double amin, double amid, double amax)
+ {
+ int id1 = getZoneIndex(table, p, 0);
+ int id2 = getZoneIndex(table, p, 1);
+ int id3 = getZoneIndex(table, p, 2);
+
+ // Deactivates everywhere..
+ if (id1 != -1) table[0][id1]->setActive(false);
+ if (id2 != -1) table[1][id2]->setActive(false);
+ if (id3 != -1) table[2][id3]->setActive(false);
+
+ if (val == -1) { // Means: no more mapping...
+ // So stay all deactivated...
+ } else {
+ int id4 = getZoneIndex(table, p, val);
+ if (id4 != -1) {
+ // Reactivate the one we edit...
+ table[val][id4]->setMappingValues(curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]);
+ table[val][id4]->setActive(true);
+ } else {
+ // Allocate a new CurveZoneControl which is 'active' by default
+ FAUSTFLOAT* zone = fZone[p];
+ table[val].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]));
+ }
+ }
+ }
+
+ void getConverter(std::vector<ZoneControl*>* table, int p, int& val, int& curve, double& amin, double& amid, double& amax)
+ {
+ int id1 = getZoneIndex(table, p, 0);
+ int id2 = getZoneIndex(table, p, 1);
+ int id3 = getZoneIndex(table, p, 2);
+
+ if (id1 != -1) {
+ val = 0;
+ curve = table[val][id1]->getCurve();
+ table[val][id1]->getMappingValues(amin, amid, amax);
+ } else if (id2 != -1) {
+ val = 1;
+ curve = table[val][id2]->getCurve();
+ table[val][id2]->getMappingValues(amin, amid, amax);
+ } else if (id3 != -1) {
+ val = 2;
+ curve = table[val][id3]->getCurve();
+ table[val][id3]->getMappingValues(amin, amid, amax);
+ } else {
+ val = -1; // No mapping
+ curve = 0;
+ amin = -100.;
+ amid = 0.;
+ amax = 100.;
+ }
+ }
+
+ public:
+
+ enum Type { kAcc = 0, kGyr = 1, kNoType };
+
+ APIUI() : fNumParameters(0), fHasScreenControl(false), fRedReader(0), fGreenReader(0), fBlueReader(0), fCurrentScale(kLin)
+ {}
+
+ virtual ~APIUI()
+ {
+ for (auto& it : fConversion) delete it;
+ for (int i = 0; i < 3; i++) {
+ for (auto& it : fAcc[i]) delete it;
+ for (auto& it : fGyr[i]) delete it;
+ }
+ delete fRedReader;
+ delete fGreenReader;
+ delete fBlueReader;
+ }
+
+ // -- widget's layouts
+
+ virtual void openTabBox(const char* label) { pushLabel(label); }
+ virtual void openHorizontalBox(const char* label) { pushLabel(label); }
+ virtual void openVerticalBox(const char* label) { pushLabel(label); }
+ virtual void closeBox() { popLabel(); }
+
+ // -- active widgets
+
+ virtual void addButton(const char* label, FAUSTFLOAT* zone)
+ {
+ addParameter(label, zone, 0, 0, 1, 1, kButton);
+ }
+
+ virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
+ {
+ addParameter(label, zone, 0, 0, 1, 1, kCheckButton);
+ }
+
+ virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+ {
+ addParameter(label, zone, init, min, max, step, kVSlider);
+ }
+
+ virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+ {
+ addParameter(label, zone, init, min, max, step, kHSlider);
+ }
+
+ virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+ {
+ addParameter(label, zone, init, min, max, step, kNumEntry);
+ }
+
+ // -- passive widgets
+
+ virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
+ {
+ addParameter(label, zone, min, min, max, (max-min)/1000.0, kHBargraph);
+ }
+
+ virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
+ {
+ addParameter(label, zone, min, min, max, (max-min)/1000.0, kVBargraph);
+ }
+
+ // -- soundfiles
+
+ virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) {}
+
+ // -- metadata declarations
+
+ virtual void declare(FAUSTFLOAT* zone, const char* key, const char* val)
+ {
+ // Keep metadata
+ fCurrentMetadata[key] = val;
+
+ if (strcmp(key, "scale") == 0) {
+ if (strcmp(val, "log") == 0) {
+ fCurrentScale = kLog;
+ } else if (strcmp(val, "exp") == 0) {
+ fCurrentScale = kExp;
+ } else {
+ fCurrentScale = kLin;
+ }
+ } else if (strcmp(key, "unit") == 0) {
+ fCurrentUnit = val;
+ } else if (strcmp(key, "acc") == 0) {
+ fCurrentAcc = val;
+ } else if (strcmp(key, "gyr") == 0) {
+ fCurrentGyr = val;
+ } else if (strcmp(key, "screencolor") == 0) {
+ fCurrentColor = val; // val = "red", "green", "blue" or "white"
+ } else if (strcmp(key, "tooltip") == 0) {
+ fCurrentTooltip = val;
+ }
+ }
+
+ virtual void declare(const char* key, const char* val)
+ {}
+
+ //-------------------------------------------------------------------------------
+ // Simple API part
+ //-------------------------------------------------------------------------------
+ int getParamsCount() { return fNumParameters; }
+ int getParamIndex(const char* path)
+ {
+ if (fPathMap.find(path) != fPathMap.end()) {
+ return fPathMap[path];
+ } else if (fLabelMap.find(path) != fLabelMap.end()) {
+ return fLabelMap[path];
+ } else {
+ return -1;
+ }
+ }
+ const char* getParamAddress(int p) { return fPaths[p].c_str(); }
+ const char* getParamLabel(int p) { return fLabels[p].c_str(); }
+ std::map<const char*, const char*> getMetadata(int p)
+ {
+ std::map<const char*, const char*> res;
+ std::map<std::string, std::string> metadata = fMetaData[p];
+ for (auto it : metadata) {
+ res[it.first.c_str()] = it.second.c_str();
+ }
+ return res;
+ }
+
+ const char* getMetadata(int p, const char* key)
+ {
+ return (fMetaData[p].find(key) != fMetaData[p].end()) ? fMetaData[p][key].c_str() : "";
+ }
+ FAUSTFLOAT getParamMin(int p) { return fMin[p]; }
+ FAUSTFLOAT getParamMax(int p) { return fMax[p]; }
+ FAUSTFLOAT getParamStep(int p) { return fStep[p]; }
+ FAUSTFLOAT getParamInit(int p) { return fInit[p]; }
+
+ FAUSTFLOAT* getParamZone(int p) { return fZone[p]; }
+ FAUSTFLOAT getParamValue(int p) { return *fZone[p]; }
+ void setParamValue(int p, FAUSTFLOAT v) { *fZone[p] = v; }
+
+ double getParamRatio(int p) { return fConversion[p]->faust2ui(*fZone[p]); }
+ void setParamRatio(int p, double r) { *fZone[p] = fConversion[p]->ui2faust(r); }
+
+ double value2ratio(int p, double r) { return fConversion[p]->faust2ui(r); }
+ double ratio2value(int p, double r) { return fConversion[p]->ui2faust(r); }
+
+ /**
+ * Return the control type (kAcc, kGyr, or -1) for a given parameter
+ *
+ * @param p - the UI parameter index
+ *
+ * @return the type
+ */
+ Type getParamType(int p)
+ {
+ if (p >= 0) {
+ if (getZoneIndex(fAcc, p, 0) != -1
+ || getZoneIndex(fAcc, p, 1) != -1
+ || getZoneIndex(fAcc, p, 2) != -1) {
+ return kAcc;
+ } else if (getZoneIndex(fGyr, p, 0) != -1
+ || getZoneIndex(fGyr, p, 1) != -1
+ || getZoneIndex(fGyr, p, 2) != -1) {
+ return kGyr;
+ }
+ }
+ return kNoType;
+ }
+
+ /**
+ * Return the Item type (kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry, kHBargraph, kVBargraph) for a given parameter
+ *
+ * @param p - the UI parameter index
+ *
+ * @return the Item type
+ */
+ ItemType getParamItemType(int p)
+ {
+ return fItemType[p];
+ }
+
+ /**
+ * Set a new value coming from an accelerometer, propagate it to all relevant FAUSTFLOAT* zones.
+ *
+ * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+ * @param value - the new value
+ *
+ */
+ void propagateAcc(int acc, double value)
+ {
+ for (size_t i = 0; i < fAcc[acc].size(); i++) {
+ fAcc[acc][i]->update(value);
+ }
+ }
+
+ /**
+ * Used to edit accelerometer curves and mapping. Set curve and related mapping for a given UI parameter.
+ *
+ * @param p - the UI parameter index
+ * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer (-1 means "no mapping")
+ * @param curve - between 0 and 3
+ * @param amin - mapping 'min' point
+ * @param amid - mapping 'middle' point
+ * @param amax - mapping 'max' point
+ *
+ */
+ void setAccConverter(int p, int acc, int curve, double amin, double amid, double amax)
+ {
+ setConverter(fAcc, p, acc, curve, amin, amid, amax);
+ }
+
+ /**
+ * Used to edit gyroscope curves and mapping. Set curve and related mapping for a given UI parameter.
+ *
+ * @param p - the UI parameter index
+ * @param acc - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope (-1 means "no mapping")
+ * @param curve - between 0 and 3
+ * @param amin - mapping 'min' point
+ * @param amid - mapping 'middle' point
+ * @param amax - mapping 'max' point
+ *
+ */
+ void setGyrConverter(int p, int gyr, int curve, double amin, double amid, double amax)
+ {
+ setConverter(fGyr, p, gyr, curve, amin, amid, amax);
+ }
+
+ /**
+ * Used to edit accelerometer curves and mapping. Get curve and related mapping for a given UI parameter.
+ *
+ * @param p - the UI parameter index
+ * @param acc - the acc value to be retrieved (-1 means "no mapping")
+ * @param curve - the curve value to be retrieved
+ * @param amin - the amin value to be retrieved
+ * @param amid - the amid value to be retrieved
+ * @param amax - the amax value to be retrieved
+ *
+ */
+ void getAccConverter(int p, int& acc, int& curve, double& amin, double& amid, double& amax)
+ {
+ getConverter(fAcc, p, acc, curve, amin, amid, amax);
+ }
+
+ /**
+ * Used to edit gyroscope curves and mapping. Get curve and related mapping for a given UI parameter.
+ *
+ * @param p - the UI parameter index
+ * @param gyr - the gyr value to be retrieved (-1 means "no mapping")
+ * @param curve - the curve value to be retrieved
+ * @param amin - the amin value to be retrieved
+ * @param amid - the amid value to be retrieved
+ * @param amax - the amax value to be retrieved
+ *
+ */
+ void getGyrConverter(int p, int& gyr, int& curve, double& amin, double& amid, double& amax)
+ {
+ getConverter(fGyr, p, gyr, curve, amin, amid, amax);
+ }
+
+ /**
+ * Set a new value coming from an gyroscope, propagate it to all relevant FAUSTFLOAT* zones.
+ *
+ * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
+ * @param value - the new value
+ *
+ */
+ void propagateGyr(int gyr, double value)
+ {
+ for (size_t i = 0; i < fGyr[gyr].size(); i++) {
+ fGyr[gyr][i]->update(value);
+ }
+ }
+
+ /**
+ * Get the number of FAUSTFLOAT* zones controlled with the accelerometer
+ *
+ * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+ * @return the number of zones
+ *
+ */
+ int getAccCount(int acc)
+ {
+ return (acc >= 0 && acc < 3) ? int(fAcc[acc].size()) : 0;
+ }
+
+ /**
+ * Get the number of FAUSTFLOAT* zones controlled with the gyroscope
+ *
+ * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
+ * @param the number of zones
+ *
+ */
+ int getGyrCount(int gyr)
+ {
+ return (gyr >= 0 && gyr < 3) ? int(fGyr[gyr].size()) : 0;
+ }
+
+ // getScreenColor() : -1 means no screen color control (no screencolor metadata found)
+ // otherwise return 0x00RRGGBB a ready to use color
+ int getScreenColor()
+ {
+ if (fHasScreenControl) {
+ int r = (fRedReader) ? fRedReader->getValue() : 0;
+ int g = (fGreenReader) ? fGreenReader->getValue() : 0;
+ int b = (fBlueReader) ? fBlueReader->getValue() : 0;
+ return (r<<16) | (g<<8) | b;
+ } else {
+ return -1;
+ }
+ }
+
+};
+
+#endif
+/************************** END APIUI.h **************************/
+
+// NOTE: "faust -scn name" changes the last line above to
+// #include <faust/name/name.h>
+
+//----------------------------------------------------------------------------
+// FAUST Generated Code
+//----------------------------------------------------------------------------
+
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+#include <algorithm>
+#include <cmath>
+#include <math.h>
+
+
+#ifndef FAUSTCLASS
+#define FAUSTCLASS compressordsp
+#endif
+
+#ifdef __APPLE__
+#define exp10f __exp10f
+#define exp10 __exp10
+#endif
+
+class compressordsp : public dsp {
+
+ private:
+
+ FAUSTFLOAT fCheckbox0;
+ FAUSTFLOAT fHslider0;
+ int fSampleRate;
+ float fConst0;
+ FAUSTFLOAT fHslider1;
+ FAUSTFLOAT fHslider2;
+ FAUSTFLOAT fHslider3;
+ float fRec5[2];
+ float fRec4[2];
+ FAUSTFLOAT fHslider4;
+ float fRec3[2];
+ float fRec2[2];
+ float fRec1[2];
+ float fRec0[2];
+ FAUSTFLOAT fHbargraph0;
+
+ public:
+
+ void metadata(Meta* m) {
+ m->declare("analyzers.lib/name", "Faust Analyzer Library");
+ m->declare("analyzers.lib/version", "0.1");
+ m->declare("author", "Julius Smith");
+ m->declare("basics.lib/name", "Faust Basic Element Library");
+ m->declare("basics.lib/version", "0.1");
+ m->declare("compressors.lib/compression_gain_mono:author", "Julius O. Smith III");
+ m->declare("compressors.lib/compression_gain_mono:copyright", "Copyright (C) 2014-2020 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+ m->declare("compressors.lib/compression_gain_mono:license", "MIT-style STK-4.3 license");
+ m->declare("compressors.lib/compressor_lad_mono:author", "Julius O. Smith III");
+ m->declare("compressors.lib/compressor_lad_mono:copyright", "Copyright (C) 2014-2020 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+ m->declare("compressors.lib/compressor_lad_mono:license", "MIT-style STK-4.3 license");
+ m->declare("compressors.lib/compressor_mono:author", "Julius O. Smith III");
+ m->declare("compressors.lib/compressor_mono:copyright", "Copyright (C) 2014-2020 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+ m->declare("compressors.lib/compressor_mono:license", "MIT-style STK-4.3 license");
+ m->declare("compressors.lib/name", "Faust Compressor Effect Library");
+ m->declare("compressors.lib/version", "0.0");
+ m->declare("description", "Compressor demo application, adapted from the Faust Library's dm.compressor_demo in demos.lib");
+ m->declare("documentation", "https://faustlibraries.grame.fr/libs/compressors/#cocompressor_mono");
+ m->declare("filename", "compressordsp.dsp");
+ m->declare("license", "MIT Style STK-4.2");
+ m->declare("maths.lib/author", "GRAME");
+ m->declare("maths.lib/copyright", "GRAME");
+ m->declare("maths.lib/license", "LGPL with exception");
+ m->declare("maths.lib/name", "Faust Math Library");
+ m->declare("maths.lib/version", "2.3");
+ m->declare("name", "compressor");
+ m->declare("platform.lib/name", "Generic Platform Library");
+ m->declare("platform.lib/version", "0.1");
+ m->declare("signals.lib/name", "Faust Signal Routing Library");
+ m->declare("signals.lib/version", "0.0");
+ m->declare("version", "0.0");
+ }
+
+ virtual int getNumInputs() {
+ return 1;
+ }
+ virtual int getNumOutputs() {
+ return 1;
+ }
+ virtual int getInputRate(int channel) {
+ int rate;
+ switch ((channel)) {
+ case 0: {
+ rate = 1;
+ break;
+ }
+ default: {
+ rate = -1;
+ break;
+ }
+ }
+ return rate;
+ }
+ virtual int getOutputRate(int channel) {
+ int rate;
+ switch ((channel)) {
+ case 0: {
+ rate = 1;
+ break;
+ }
+ default: {
+ rate = -1;
+ break;
+ }
+ }
+ return rate;
+ }
+
+ static void classInit(int sample_rate) {
+ }
+
+ virtual void instanceConstants(int sample_rate) {
+ fSampleRate = sample_rate;
+ fConst0 = (1.0f / std::min<float>(192000.0f, std::max<float>(1.0f, float(fSampleRate))));
+ }
+
+ virtual void instanceResetUserInterface() {
+ fCheckbox0 = FAUSTFLOAT(0.0f);
+ fHslider0 = FAUSTFLOAT(2.0f);
+ fHslider1 = FAUSTFLOAT(15.0f);
+ fHslider2 = FAUSTFLOAT(2.0f);
+ fHslider3 = FAUSTFLOAT(40.0f);
+ fHslider4 = FAUSTFLOAT(-24.0f);
+ }
+
+ virtual void instanceClear() {
+ for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) {
+ fRec5[l0] = 0.0f;
+ }
+ for (int l1 = 0; (l1 < 2); l1 = (l1 + 1)) {
+ fRec4[l1] = 0.0f;
+ }
+ for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) {
+ fRec3[l2] = 0.0f;
+ }
+ for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) {
+ fRec2[l3] = 0.0f;
+ }
+ for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) {
+ fRec1[l4] = 0.0f;
+ }
+ for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) {
+ fRec0[l5] = 0.0f;
+ }
+ }
+
+ virtual void init(int sample_rate) {
+ classInit(sample_rate);
+ instanceInit(sample_rate);
+ }
+ virtual void instanceInit(int sample_rate) {
+ instanceConstants(sample_rate);
+ instanceResetUserInterface();
+ instanceClear();
+ }
+
+ virtual compressordsp* clone() {
+ return new compressordsp();
+ }
+
+ virtual int getSampleRate() {
+ return fSampleRate;
+ }
+
+ virtual void buildUserInterface(UI* ui_interface) {
+ ui_interface->declare(0, "tooltip", "References: https://faustlibraries.grame.fr/libs/compressors/ http://en.wikipedia.org/wiki/Dynamic_range_compression");
+ ui_interface->openVerticalBox("COMPRESSOR");
+ ui_interface->declare(0, "0", "");
+ ui_interface->openHorizontalBox("0x00");
+ ui_interface->declare(&fCheckbox0, "0", "");
+ ui_interface->declare(&fCheckbox0, "tooltip", "When this is checked, the compressor has no effect");
+ ui_interface->addCheckButton("Bypass", &fCheckbox0);
+ ui_interface->declare(&fHbargraph0, "1", "");
+ ui_interface->declare(&fHbargraph0, "tooltip", "Compressor gain in dB");
+ ui_interface->declare(&fHbargraph0, "unit", "dB");
+ ui_interface->addHorizontalBargraph("Compressor Gain", &fHbargraph0, -50.0f, 10.0f);
+ ui_interface->closeBox();
+ ui_interface->declare(0, "1", "");
+ ui_interface->openHorizontalBox("0x00");
+ ui_interface->declare(0, "3", "");
+ ui_interface->openHorizontalBox("Compression Control");
+ ui_interface->declare(&fHslider2, "0", "");
+ ui_interface->declare(&fHslider2, "style", "knob");
+ ui_interface->declare(&fHslider2, "tooltip", "A compression Ratio of N means that for each N dB increase in input signal level above Threshold, the output level goes up 1 dB");
+ ui_interface->addHorizontalSlider("Ratio", &fHslider2, 2.0f, 1.0f, 20.0f, 0.100000001f);
+ ui_interface->declare(&fHslider4, "1", "");
+ ui_interface->declare(&fHslider4, "style", "knob");
+ ui_interface->declare(&fHslider4, "tooltip", "When the signal level exceeds the Threshold (in dB), its level is compressed according to the Ratio");
+ ui_interface->declare(&fHslider4, "unit", "dB");
+ ui_interface->addHorizontalSlider("Threshold", &fHslider4, -24.0f, -100.0f, 10.0f, 0.100000001f);
+ ui_interface->closeBox();
+ ui_interface->declare(0, "4", "");
+ ui_interface->openHorizontalBox("Compression Response");
+ ui_interface->declare(&fHslider1, "1", "");
+ ui_interface->declare(&fHslider1, "scale", "log");
+ ui_interface->declare(&fHslider1, "style", "knob");
+ ui_interface->declare(&fHslider1, "tooltip", "Time constant in ms (1/e smoothing time) for the compression gain to approach (exponentially) a new lower target level (the compression `kicking in')");
+ ui_interface->declare(&fHslider1, "unit", "ms");
+ ui_interface->addHorizontalSlider("Attack", &fHslider1, 15.0f, 1.0f, 1000.0f, 0.100000001f);
+ ui_interface->declare(&fHslider3, "2", "");
+ ui_interface->declare(&fHslider3, "scale", "log");
+ ui_interface->declare(&fHslider3, "style", "knob");
+ ui_interface->declare(&fHslider3, "tooltip", "Time constant in ms (1/e smoothing time) for the compression gain to approach (exponentially) a new higher target level (the compression 'releasing')");
+ ui_interface->declare(&fHslider3, "unit", "ms");
+ ui_interface->addHorizontalSlider("Release", &fHslider3, 40.0f, 1.0f, 1000.0f, 0.100000001f);
+ ui_interface->closeBox();
+ ui_interface->closeBox();
+ ui_interface->declare(&fHslider0, "5", "");
+ ui_interface->declare(&fHslider0, "tooltip", "The compressed-signal output level is increased by this amount (in dB) to make up for the level lost due to compression");
+ ui_interface->declare(&fHslider0, "unit", "dB");
+ ui_interface->addHorizontalSlider("MakeUpGain", &fHslider0, 2.0f, -96.0f, 96.0f, 0.100000001f);
+ ui_interface->closeBox();
+ }
+
+ virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
+ FAUSTFLOAT* input0 = inputs[0];
+ FAUSTFLOAT* output0 = outputs[0];
+ int iSlow0 = int(float(fCheckbox0));
+ float fSlow1 = std::pow(10.0f, (0.0500000007f * float(fHslider0)));
+ float fSlow2 = std::max<float>(fConst0, (0.00100000005f * float(fHslider1)));
+ float fSlow3 = (0.5f * fSlow2);
+ int iSlow4 = (std::fabs(fSlow3) < 1.1920929e-07f);
+ float fSlow5 = (iSlow4 ? 0.0f : std::exp((0.0f - (fConst0 / (iSlow4 ? 1.0f : fSlow3)))));
+ float fSlow6 = ((1.0f / std::max<float>(1.00000001e-07f, float(fHslider2))) + -1.0f);
+ int iSlow7 = (std::fabs(fSlow2) < 1.1920929e-07f);
+ float fSlow8 = (iSlow7 ? 0.0f : std::exp((0.0f - (fConst0 / (iSlow7 ? 1.0f : fSlow2)))));
+ float fSlow9 = std::max<float>(fConst0, (0.00100000005f * float(fHslider3)));
+ int iSlow10 = (std::fabs(fSlow9) < 1.1920929e-07f);
+ float fSlow11 = (iSlow10 ? 0.0f : std::exp((0.0f - (fConst0 / (iSlow10 ? 1.0f : fSlow9)))));
+ float fSlow12 = float(fHslider4);
+ float fSlow13 = (1.0f - fSlow5);
+ for (int i = 0; (i < count); i = (i + 1)) {
+ float fTemp0 = float(input0[i]);
+ float fTemp1 = (iSlow0 ? 0.0f : fTemp0);
+ float fTemp2 = std::fabs(fTemp1);
+ float fTemp3 = ((fRec4[1] > fTemp2) ? fSlow11 : fSlow8);
+ fRec5[0] = ((fRec5[1] * fTemp3) + (fTemp2 * (1.0f - fTemp3)));
+ fRec4[0] = fRec5[0];
+ fRec3[0] = ((fRec3[1] * fSlow5) + (fSlow6 * (std::max<float>(((20.0f * std::log10(fRec4[0])) - fSlow12), 0.0f) * fSlow13)));
+ float fTemp4 = (fTemp1 * std::pow(10.0f, (0.0500000007f * fRec3[0])));
+ float fTemp5 = std::fabs(fTemp4);
+ float fTemp6 = ((fRec1[1] > fTemp5) ? fSlow11 : fSlow8);
+ fRec2[0] = ((fRec2[1] * fTemp6) + (fTemp5 * (1.0f - fTemp6)));
+ fRec1[0] = fRec2[0];
+ fRec0[0] = ((fSlow5 * fRec0[1]) + (fSlow6 * (std::max<float>(((20.0f * std::log10(fRec1[0])) - fSlow12), 0.0f) * fSlow13)));
+ fHbargraph0 = FAUSTFLOAT((20.0f * std::log10(std::pow(10.0f, (0.0500000007f * fRec0[0])))));
+ output0[i] = FAUSTFLOAT((iSlow0 ? fTemp0 : (fSlow1 * fTemp4)));
+ fRec5[1] = fRec5[0];
+ fRec4[1] = fRec4[0];
+ fRec3[1] = fRec3[0];
+ fRec2[1] = fRec2[0];
+ fRec1[1] = fRec1[0];
+ fRec0[1] = fRec0[0];
+ }
+ }
+
+};
+
+#endif
diff --git a/src/freeverbdsp.h b/src/freeverbdsp.h
new file mode 100644
index 0000000..4ccaa5e
--- /dev/null
+++ b/src/freeverbdsp.h
@@ -0,0 +1,2168 @@
+/* ------------------------------------------------------------
+author: "Romain Michon"
+license: "LGPL"
+name: "freeverb"
+version: "0.0"
+Code generated with Faust 2.28.6 (https://faust.grame.fr)
+Compilation options: -lang cpp -inpl -scal -ftz 0
+------------------------------------------------------------ */
+
+#ifndef __freeverbdsp_H__
+#define __freeverbdsp_H__
+
+// NOTE: ANY INCLUDE-GUARD HERE MUST BE DERIVED FROM THE CLASS NAME
+//
+// faust2header.cpp - FAUST Architecture File
+// This is a simple variation of matlabplot.cpp in the Faust distribution
+// aimed at creating a simple C++ header file (.h) containing a Faust DSP.
+// See the Makefile for how to use it.
+
+/************************** BEGIN dsp.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __dsp__
+#define __dsp__
+
+#include <string>
+#include <vector>
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+struct UI;
+struct Meta;
+
+/**
+ * DSP memory manager.
+ */
+
+struct dsp_memory_manager {
+
+ virtual ~dsp_memory_manager() {}
+
+ virtual void* allocate(size_t size) = 0;
+ virtual void destroy(void* ptr) = 0;
+
+};
+
+/**
+* Signal processor definition.
+*/
+
+class dsp {
+
+ public:
+
+ dsp() {}
+ virtual ~dsp() {}
+
+ /* Return instance number of audio inputs */
+ virtual int getNumInputs() = 0;
+
+ /* Return instance number of audio outputs */
+ virtual int getNumOutputs() = 0;
+
+ /**
+ * Trigger the ui_interface parameter with instance specific calls
+ * to 'openTabBox', 'addButton', 'addVerticalSlider'... in order to build the UI.
+ *
+ * @param ui_interface - the user interface builder
+ */
+ virtual void buildUserInterface(UI* ui_interface) = 0;
+
+ /* Returns the sample rate currently used by the instance */
+ virtual int getSampleRate() = 0;
+
+ /**
+ * Global init, calls the following methods:
+ * - static class 'classInit': static tables initialization
+ * - 'instanceInit': constants and instance state initialization
+ *
+ * @param sample_rate - the sampling rate in Hertz
+ */
+ virtual void init(int sample_rate) = 0;
+
+ /**
+ * Init instance state
+ *
+ * @param sample_rate - the sampling rate in Hertz
+ */
+ virtual void instanceInit(int sample_rate) = 0;
+
+ /**
+ * Init instance constant state
+ *
+ * @param sample_rate - the sampling rate in Hertz
+ */
+ virtual void instanceConstants(int sample_rate) = 0;
+
+ /* Init default control parameters values */
+ virtual void instanceResetUserInterface() = 0;
+
+ /* Init instance state (delay lines...) */
+ virtual void instanceClear() = 0;
+
+ /**
+ * Return a clone of the instance.
+ *
+ * @return a copy of the instance on success, otherwise a null pointer.
+ */
+ virtual dsp* clone() = 0;
+
+ /**
+ * Trigger the Meta* parameter with instance specific calls to 'declare' (key, value) metadata.
+ *
+ * @param m - the Meta* meta user
+ */
+ virtual void metadata(Meta* m) = 0;
+
+ /**
+ * DSP instance computation, to be called with successive in/out audio buffers.
+ *
+ * @param count - the number of frames to compute
+ * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
+ * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
+ *
+ */
+ virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) = 0;
+
+ /**
+ * DSP instance computation: alternative method to be used by subclasses.
+ *
+ * @param date_usec - the timestamp in microsec given by audio driver.
+ * @param count - the number of frames to compute
+ * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
+ * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
+ *
+ */
+ virtual void compute(double /*date_usec*/, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { compute(count, inputs, outputs); }
+
+};
+
+/**
+ * Generic DSP decorator.
+ */
+
+class decorator_dsp : public dsp {
+
+ protected:
+
+ dsp* fDSP;
+
+ public:
+
+ decorator_dsp(dsp* dsp = nullptr):fDSP(dsp) {}
+ virtual ~decorator_dsp() { delete fDSP; }
+
+ virtual int getNumInputs() { return fDSP->getNumInputs(); }
+ virtual int getNumOutputs() { return fDSP->getNumOutputs(); }
+ virtual void buildUserInterface(UI* ui_interface) { fDSP->buildUserInterface(ui_interface); }
+ virtual int getSampleRate() { return fDSP->getSampleRate(); }
+ virtual void init(int sample_rate) { fDSP->init(sample_rate); }
+ virtual void instanceInit(int sample_rate) { fDSP->instanceInit(sample_rate); }
+ virtual void instanceConstants(int sample_rate) { fDSP->instanceConstants(sample_rate); }
+ virtual void instanceResetUserInterface() { fDSP->instanceResetUserInterface(); }
+ virtual void instanceClear() { fDSP->instanceClear(); }
+ virtual decorator_dsp* clone() { return new decorator_dsp(fDSP->clone()); }
+ virtual void metadata(Meta* m) { fDSP->metadata(m); }
+ // Beware: subclasses usually have to overload the two 'compute' methods
+ virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(count, inputs, outputs); }
+ virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(date_usec, count, inputs, outputs); }
+
+};
+
+/**
+ * DSP factory class.
+ */
+
+class dsp_factory {
+
+ protected:
+
+ // So that to force sub-classes to use deleteDSPFactory(dsp_factory* factory);
+ virtual ~dsp_factory() {}
+
+ public:
+
+ virtual std::string getName() = 0;
+ virtual std::string getSHAKey() = 0;
+ virtual std::string getDSPCode() = 0;
+ virtual std::string getCompileOptions() = 0;
+ virtual std::vector<std::string> getLibraryList() = 0;
+ virtual std::vector<std::string> getIncludePathnames() = 0;
+
+ virtual dsp* createDSPInstance() = 0;
+
+ virtual void setMemoryManager(dsp_memory_manager* manager) = 0;
+ virtual dsp_memory_manager* getMemoryManager() = 0;
+
+};
+
+/**
+ * On Intel set FZ (Flush to Zero) and DAZ (Denormals Are Zero)
+ * flags to avoid costly denormals.
+ */
+
+#ifdef __SSE__
+ #include <xmmintrin.h>
+ #ifdef __SSE2__
+ #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
+ #else
+ #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
+ #endif
+#else
+ #define AVOIDDENORMALS
+#endif
+
+#endif
+/************************** END dsp.h **************************/
+
+/************************** BEGIN APIUI.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef API_UI_H
+#define API_UI_H
+
+#include <sstream>
+#include <string>
+#include <vector>
+#include <iostream>
+#include <map>
+
+/************************** BEGIN meta.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __meta__
+#define __meta__
+
+struct Meta
+{
+ virtual ~Meta() {};
+ virtual void declare(const char* key, const char* value) = 0;
+
+};
+
+#endif
+/************************** END meta.h **************************/
+/************************** BEGIN UI.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2020 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __UI_H__
+#define __UI_H__
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+/*******************************************************************************
+ * UI : Faust DSP User Interface
+ * User Interface as expected by the buildUserInterface() method of a DSP.
+ * This abstract class contains only the method that the Faust compiler can
+ * generate to describe a DSP user interface.
+ ******************************************************************************/
+
+struct Soundfile;
+
+template <typename REAL>
+struct UIReal
+{
+ UIReal() {}
+ virtual ~UIReal() {}
+
+ // -- widget's layouts
+
+ virtual void openTabBox(const char* label) = 0;
+ virtual void openHorizontalBox(const char* label) = 0;
+ virtual void openVerticalBox(const char* label) = 0;
+ virtual void closeBox() = 0;
+
+ // -- active widgets
+
+ virtual void addButton(const char* label, REAL* zone) = 0;
+ virtual void addCheckButton(const char* label, REAL* zone) = 0;
+ virtual void addVerticalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
+ virtual void addHorizontalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
+ virtual void addNumEntry(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
+
+ // -- passive widgets
+
+ virtual void addHorizontalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
+ virtual void addVerticalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
+
+ // -- soundfiles
+
+ virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) = 0;
+
+ // -- metadata declarations
+
+ virtual void declare(REAL* zone, const char* key, const char* val) {}
+};
+
+struct UI : public UIReal<FAUSTFLOAT>
+{
+ UI() {}
+ virtual ~UI() {}
+};
+
+#endif
+/************************** END UI.h **************************/
+/************************** BEGIN PathBuilder.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef FAUST_PATHBUILDER_H
+#define FAUST_PATHBUILDER_H
+
+#include <vector>
+#include <string>
+#include <algorithm>
+
+/*******************************************************************************
+ * PathBuilder : Faust User Interface
+ * Helper class to build complete hierarchical path for UI items.
+ ******************************************************************************/
+
+class PathBuilder
+{
+
+ protected:
+
+ std::vector<std::string> fControlsLevel;
+
+ public:
+
+ PathBuilder() {}
+ virtual ~PathBuilder() {}
+
+ std::string buildPath(const std::string& label)
+ {
+ std::string res = "/";
+ for (size_t i = 0; i < fControlsLevel.size(); i++) {
+ res += fControlsLevel[i];
+ res += "/";
+ }
+ res += label;
+ std::replace(res.begin(), res.end(), ' ', '_');
+ return res;
+ }
+
+ std::string buildLabel(std::string label)
+ {
+ std::replace(label.begin(), label.end(), ' ', '_');
+ return label;
+ }
+
+ void pushLabel(const std::string& label) { fControlsLevel.push_back(label); }
+ void popLabel() { fControlsLevel.pop_back(); }
+
+};
+
+#endif // FAUST_PATHBUILDER_H
+/************************** END PathBuilder.h **************************/
+/************************** BEGIN ValueConverter.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __ValueConverter__
+#define __ValueConverter__
+
+/***************************************************************************************
+ ValueConverter.h
+ (GRAME, Copyright 2015-2019)
+
+Set of conversion objects used to map user interface values (for example a gui slider
+delivering values between 0 and 1) to faust values (for example a vslider between
+20 and 20000) using a log scale.
+
+-- Utilities
+
+Range(lo,hi) : clip a value x between lo and hi
+Interpolator(lo,hi,v1,v2) : Maps a value x between lo and hi to a value y between v1 and v2
+Interpolator3pt(lo,mi,hi,v1,vm,v2) : Map values between lo mid hi to values between v1 vm v2
+
+-- Value Converters
+
+ValueConverter::ui2faust(x)
+ValueConverter::faust2ui(x)
+
+-- ValueConverters used for sliders depending of the scale
+
+LinearValueConverter(umin, umax, fmin, fmax)
+LinearValueConverter2(lo, mi, hi, v1, vm, v2) using 2 segments
+LogValueConverter(umin, umax, fmin, fmax)
+ExpValueConverter(umin, umax, fmin, fmax)
+
+-- ValueConverters used for accelerometers based on 3 points
+
+AccUpConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 0
+AccDownConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 1
+AccUpDownConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 2
+AccDownUpConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 3
+
+-- lists of ZoneControl are used to implement accelerometers metadata for each axes
+
+ZoneControl(zone, valueConverter) : a zone with an accelerometer data converter
+
+-- ZoneReader are used to implement screencolor metadata
+
+ZoneReader(zone, valueConverter) : a zone with a data converter
+
+****************************************************************************************/
+
+#include <float.h>
+#include <algorithm> // std::max
+#include <cmath>
+#include <vector>
+#include <assert.h>
+
+//--------------------------------------------------------------------------------------
+// Interpolator(lo,hi,v1,v2)
+// Maps a value x between lo and hi to a value y between v1 and v2
+// y = v1 + (x-lo)/(hi-lo)*(v2-v1)
+// y = v1 + (x-lo) * coef with coef = (v2-v1)/(hi-lo)
+// y = v1 + x*coef - lo*coef
+// y = v1 - lo*coef + x*coef
+// y = offset + x*coef with offset = v1 - lo*coef
+//--------------------------------------------------------------------------------------
+class Interpolator
+{
+ private:
+
+ //--------------------------------------------------------------------------------------
+ // Range(lo,hi) clip a value between lo and hi
+ //--------------------------------------------------------------------------------------
+ struct Range
+ {
+ double fLo;
+ double fHi;
+
+ Range(double x, double y) : fLo(std::min<double>(x,y)), fHi(std::max<double>(x,y)) {}
+ double operator()(double x) { return (x<fLo) ? fLo : (x>fHi) ? fHi : x; }
+ };
+
+
+ Range fRange;
+ double fCoef;
+ double fOffset;
+
+ public:
+
+ Interpolator(double lo, double hi, double v1, double v2) : fRange(lo,hi)
+ {
+ if (hi != lo) {
+ // regular case
+ fCoef = (v2-v1)/(hi-lo);
+ fOffset = v1 - lo*fCoef;
+ } else {
+ // degenerate case, avoids division by zero
+ fCoef = 0;
+ fOffset = (v1+v2)/2;
+ }
+ }
+ double operator()(double v)
+ {
+ double x = fRange(v);
+ return fOffset + x*fCoef;
+ }
+
+ void getLowHigh(double& amin, double& amax)
+ {
+ amin = fRange.fLo;
+ amax = fRange.fHi;
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Interpolator3pt(lo,mi,hi,v1,vm,v2)
+// Map values between lo mid hi to values between v1 vm v2
+//--------------------------------------------------------------------------------------
+class Interpolator3pt
+{
+
+ private:
+
+ Interpolator fSegment1;
+ Interpolator fSegment2;
+ double fMid;
+
+ public:
+
+ Interpolator3pt(double lo, double mi, double hi, double v1, double vm, double v2) :
+ fSegment1(lo, mi, v1, vm),
+ fSegment2(mi, hi, vm, v2),
+ fMid(mi) {}
+ double operator()(double x) { return (x < fMid) ? fSegment1(x) : fSegment2(x); }
+
+ void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fSegment1.getLowHigh(amin, amid);
+ fSegment2.getLowHigh(amid, amax);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Abstract ValueConverter class. Converts values between UI and Faust representations
+//--------------------------------------------------------------------------------------
+class ValueConverter
+{
+
+ public:
+
+ virtual ~ValueConverter() {}
+ virtual double ui2faust(double x) = 0;
+ virtual double faust2ui(double x) = 0;
+};
+
+//--------------------------------------------------------------------------------------
+// A converter than can be updated
+//--------------------------------------------------------------------------------------
+
+class UpdatableValueConverter : public ValueConverter {
+
+ protected:
+
+ bool fActive;
+
+ public:
+
+ UpdatableValueConverter():fActive(true)
+ {}
+ virtual ~UpdatableValueConverter()
+ {}
+
+ virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max) = 0;
+ virtual void getMappingValues(double& amin, double& amid, double& amax) = 0;
+
+ void setActive(bool on_off) { fActive = on_off; }
+ bool getActive() { return fActive; }
+
+};
+
+
+//--------------------------------------------------------------------------------------
+// Linear conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class LinearValueConverter : public ValueConverter
+{
+
+ private:
+
+ Interpolator fUI2F;
+ Interpolator fF2UI;
+
+ public:
+
+ LinearValueConverter(double umin, double umax, double fmin, double fmax) :
+ fUI2F(umin,umax,fmin,fmax), fF2UI(fmin,fmax,umin,umax)
+ {}
+
+ LinearValueConverter() : fUI2F(0.,0.,0.,0.), fF2UI(0.,0.,0.,0.)
+ {}
+ virtual double ui2faust(double x) { return fUI2F(x); }
+ virtual double faust2ui(double x) { return fF2UI(x); }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Two segments linear conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class LinearValueConverter2 : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fUI2F;
+ Interpolator3pt fF2UI;
+
+ public:
+
+ LinearValueConverter2(double amin, double amid, double amax, double min, double init, double max) :
+ fUI2F(amin, amid, amax, min, init, max), fF2UI(min, init, max, amin, amid, amax)
+ {}
+
+ LinearValueConverter2() : fUI2F(0.,0.,0.,0.,0.,0.), fF2UI(0.,0.,0.,0.,0.,0.)
+ {}
+
+ virtual double ui2faust(double x) { return fUI2F(x); }
+ virtual double faust2ui(double x) { return fF2UI(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max)
+ {
+ fUI2F = Interpolator3pt(amin, amid, amax, min, init, max);
+ fF2UI = Interpolator3pt(min, init, max, amin, amid, amax);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fUI2F.getMappingValues(amin, amid, amax);
+ }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Logarithmic conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class LogValueConverter : public LinearValueConverter
+{
+
+ public:
+
+ LogValueConverter(double umin, double umax, double fmin, double fmax) :
+ LinearValueConverter(umin, umax, std::log(std::max<double>(DBL_MIN, fmin)), std::log(std::max<double>(DBL_MIN, fmax)))
+ {}
+
+ virtual double ui2faust(double x) { return std::exp(LinearValueConverter::ui2faust(x)); }
+ virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::log(std::max<double>(x, DBL_MIN))); }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Exponential conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class ExpValueConverter : public LinearValueConverter
+{
+
+ public:
+
+ ExpValueConverter(double umin, double umax, double fmin, double fmax) :
+ LinearValueConverter(umin, umax, std::min<double>(DBL_MAX, std::exp(fmin)), std::min<double>(DBL_MAX, std::exp(fmax)))
+ {}
+
+ virtual double ui2faust(double x) { return std::log(LinearValueConverter::ui2faust(x)); }
+ virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::min<double>(DBL_MAX, std::exp(x))); }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using an Up curve (curve 0)
+//--------------------------------------------------------------------------------------
+class AccUpConverter : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fA2F;
+ Interpolator3pt fF2A;
+
+ public:
+
+ AccUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
+ fA2F(amin,amid,amax,fmin,fmid,fmax),
+ fF2A(fmin,fmid,fmax,amin,amid,amax)
+ {}
+
+ virtual double ui2faust(double x) { return fA2F(x); }
+ virtual double faust2ui(double x) { return fF2A(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
+ {
+ //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+ fA2F = Interpolator3pt(amin, amid, amax, fmin, fmid, fmax);
+ fF2A = Interpolator3pt(fmin, fmid, fmax, amin, amid, amax);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fA2F.getMappingValues(amin, amid, amax);
+ }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using a Down curve (curve 1)
+//--------------------------------------------------------------------------------------
+class AccDownConverter : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fA2F;
+ Interpolator3pt fF2A;
+
+ public:
+
+ AccDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
+ fA2F(amin,amid,amax,fmax,fmid,fmin),
+ fF2A(fmin,fmid,fmax,amax,amid,amin)
+ {}
+
+ virtual double ui2faust(double x) { return fA2F(x); }
+ virtual double faust2ui(double x) { return fF2A(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
+ {
+ //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+ fA2F = Interpolator3pt(amin, amid, amax, fmax, fmid, fmin);
+ fF2A = Interpolator3pt(fmin, fmid, fmax, amax, amid, amin);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fA2F.getMappingValues(amin, amid, amax);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using an Up-Down curve (curve 2)
+//--------------------------------------------------------------------------------------
+class AccUpDownConverter : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fA2F;
+ Interpolator fF2A;
+
+ public:
+
+ AccUpDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
+ fA2F(amin,amid,amax,fmin,fmax,fmin),
+ fF2A(fmin,fmax,amin,amax) // Special, pseudo inverse of a non monotonic function
+ {}
+
+ virtual double ui2faust(double x) { return fA2F(x); }
+ virtual double faust2ui(double x) { return fF2A(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
+ {
+ //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+ fA2F = Interpolator3pt(amin, amid, amax, fmin, fmax, fmin);
+ fF2A = Interpolator(fmin, fmax, amin, amax);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fA2F.getMappingValues(amin, amid, amax);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using a Down-Up curve (curve 3)
+//--------------------------------------------------------------------------------------
+class AccDownUpConverter : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fA2F;
+ Interpolator fF2A;
+
+ public:
+
+ AccDownUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
+ fA2F(amin,amid,amax,fmax,fmin,fmax),
+ fF2A(fmin,fmax,amin,amax) // Special, pseudo inverse of a non monotonic function
+ {}
+
+ virtual double ui2faust(double x) { return fA2F(x); }
+ virtual double faust2ui(double x) { return fF2A(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
+ {
+ //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+ fA2F = Interpolator3pt(amin, amid, amax, fmax, fmin, fmax);
+ fF2A = Interpolator(fmin, fmax, amin, amax);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fA2F.getMappingValues(amin, amid, amax);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Base class for ZoneControl
+//--------------------------------------------------------------------------------------
+class ZoneControl
+{
+
+ protected:
+
+ FAUSTFLOAT* fZone;
+
+ public:
+
+ ZoneControl(FAUSTFLOAT* zone) : fZone(zone) {}
+ virtual ~ZoneControl() {}
+
+ virtual void update(double v) const {}
+
+ virtual void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max) {}
+ virtual void getMappingValues(double& amin, double& amid, double& amax) {}
+
+ FAUSTFLOAT* getZone() { return fZone; }
+
+ virtual void setActive(bool on_off) {}
+ virtual bool getActive() { return false; }
+
+ virtual int getCurve() { return -1; }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Useful to implement accelerometers metadata as a list of ZoneControl for each axes
+//--------------------------------------------------------------------------------------
+class ConverterZoneControl : public ZoneControl
+{
+
+ protected:
+
+ ValueConverter* fValueConverter;
+
+ public:
+
+ ConverterZoneControl(FAUSTFLOAT* zone, ValueConverter* converter) : ZoneControl(zone), fValueConverter(converter) {}
+ virtual ~ConverterZoneControl() { delete fValueConverter; } // Assuming fValueConverter is not kept elsewhere...
+
+ virtual void update(double v) const { *fZone = fValueConverter->ui2faust(v); }
+
+ ValueConverter* getConverter() { return fValueConverter; }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Association of a zone and a four value converter, each one for each possible curve.
+// Useful to implement accelerometers metadata as a list of ZoneControl for each axes
+//--------------------------------------------------------------------------------------
+class CurveZoneControl : public ZoneControl
+{
+
+ private:
+
+ std::vector<UpdatableValueConverter*> fValueConverters;
+ int fCurve;
+
+ public:
+
+ CurveZoneControl(FAUSTFLOAT* zone, int curve, double amin, double amid, double amax, double min, double init, double max) : ZoneControl(zone), fCurve(0)
+ {
+ assert(curve >= 0 && curve <= 3);
+ fValueConverters.push_back(new AccUpConverter(amin, amid, amax, min, init, max));
+ fValueConverters.push_back(new AccDownConverter(amin, amid, amax, min, init, max));
+ fValueConverters.push_back(new AccUpDownConverter(amin, amid, amax, min, init, max));
+ fValueConverters.push_back(new AccDownUpConverter(amin, amid, amax, min, init, max));
+ fCurve = curve;
+ }
+ virtual ~CurveZoneControl()
+ {
+ std::vector<UpdatableValueConverter*>::iterator it;
+ for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
+ delete(*it);
+ }
+ }
+ void update(double v) const { if (fValueConverters[fCurve]->getActive()) *fZone = fValueConverters[fCurve]->ui2faust(v); }
+
+ void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max)
+ {
+ fValueConverters[curve]->setMappingValues(amin, amid, amax, min, init, max);
+ fCurve = curve;
+ }
+
+ void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fValueConverters[fCurve]->getMappingValues(amin, amid, amax);
+ }
+
+ void setActive(bool on_off)
+ {
+ std::vector<UpdatableValueConverter*>::iterator it;
+ for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
+ (*it)->setActive(on_off);
+ }
+ }
+
+ int getCurve() { return fCurve; }
+};
+
+class ZoneReader
+{
+
+ private:
+
+ FAUSTFLOAT* fZone;
+ Interpolator fInterpolator;
+
+ public:
+
+ ZoneReader(FAUSTFLOAT* zone, double lo, double hi) : fZone(zone), fInterpolator(lo, hi, 0, 255) {}
+
+ virtual ~ZoneReader() {}
+
+ int getValue()
+ {
+ return (fZone != nullptr) ? int(fInterpolator(*fZone)) : 127;
+ }
+
+};
+
+#endif
+/************************** END ValueConverter.h **************************/
+
+class APIUI : public PathBuilder, public Meta, public UI
+{
+ public:
+
+ enum ItemType { kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry, kHBargraph, kVBargraph };
+
+ protected:
+
+ enum { kLin = 0, kLog = 1, kExp = 2 };
+
+ int fNumParameters;
+ std::vector<std::string> fPaths;
+ std::vector<std::string> fLabels;
+ std::map<std::string, int> fPathMap;
+ std::map<std::string, int> fLabelMap;
+ std::vector<ValueConverter*> fConversion;
+ std::vector<FAUSTFLOAT*> fZone;
+ std::vector<FAUSTFLOAT> fInit;
+ std::vector<FAUSTFLOAT> fMin;
+ std::vector<FAUSTFLOAT> fMax;
+ std::vector<FAUSTFLOAT> fStep;
+ std::vector<ItemType> fItemType;
+ std::vector<std::map<std::string, std::string> > fMetaData;
+ std::vector<ZoneControl*> fAcc[3];
+ std::vector<ZoneControl*> fGyr[3];
+
+ // Screen color control
+ // "...[screencolor:red]..." etc.
+ bool fHasScreenControl; // true if control screen color metadata
+ ZoneReader* fRedReader;
+ ZoneReader* fGreenReader;
+ ZoneReader* fBlueReader;
+
+ // Current values controlled by metadata
+ std::string fCurrentUnit;
+ int fCurrentScale;
+ std::string fCurrentAcc;
+ std::string fCurrentGyr;
+ std::string fCurrentColor;
+ std::string fCurrentTooltip;
+ std::map<std::string, std::string> fCurrentMetadata;
+
+ // Add a generic parameter
+ virtual void addParameter(const char* label,
+ FAUSTFLOAT* zone,
+ FAUSTFLOAT init,
+ FAUSTFLOAT min,
+ FAUSTFLOAT max,
+ FAUSTFLOAT step,
+ ItemType type)
+ {
+ std::string path = buildPath(label);
+ fPathMap[path] = fLabelMap[label] = fNumParameters++;
+ fPaths.push_back(path);
+ fLabels.push_back(label);
+ fZone.push_back(zone);
+ fInit.push_back(init);
+ fMin.push_back(min);
+ fMax.push_back(max);
+ fStep.push_back(step);
+ fItemType.push_back(type);
+
+ // handle scale metadata
+ switch (fCurrentScale) {
+ case kLin:
+ fConversion.push_back(new LinearValueConverter(0, 1, min, max));
+ break;
+ case kLog:
+ fConversion.push_back(new LogValueConverter(0, 1, min, max));
+ break;
+ case kExp: fConversion.push_back(new ExpValueConverter(0, 1, min, max));
+ break;
+ }
+ fCurrentScale = kLin;
+
+ if (fCurrentAcc.size() > 0 && fCurrentGyr.size() > 0) {
+ std::cerr << "warning : 'acc' and 'gyr' metadata used for the same " << label << " parameter !!\n";
+ }
+
+ // handle acc metadata "...[acc : <axe> <curve> <amin> <amid> <amax>]..."
+ if (fCurrentAcc.size() > 0) {
+ std::istringstream iss(fCurrentAcc);
+ int axe, curve;
+ double amin, amid, amax;
+ iss >> axe >> curve >> amin >> amid >> amax;
+
+ if ((0 <= axe) && (axe < 3) &&
+ (0 <= curve) && (curve < 4) &&
+ (amin < amax) && (amin <= amid) && (amid <= amax))
+ {
+ fAcc[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
+ } else {
+ std::cerr << "incorrect acc metadata : " << fCurrentAcc << std::endl;
+ }
+ fCurrentAcc = "";
+ }
+
+ // handle gyr metadata "...[gyr : <axe> <curve> <amin> <amid> <amax>]..."
+ if (fCurrentGyr.size() > 0) {
+ std::istringstream iss(fCurrentGyr);
+ int axe, curve;
+ double amin, amid, amax;
+ iss >> axe >> curve >> amin >> amid >> amax;
+
+ if ((0 <= axe) && (axe < 3) &&
+ (0 <= curve) && (curve < 4) &&
+ (amin < amax) && (amin <= amid) && (amid <= amax))
+ {
+ fGyr[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
+ } else {
+ std::cerr << "incorrect gyr metadata : " << fCurrentGyr << std::endl;
+ }
+ fCurrentGyr = "";
+ }
+
+ // handle screencolor metadata "...[screencolor:red|green|blue|white]..."
+ if (fCurrentColor.size() > 0) {
+ if ((fCurrentColor == "red") && (fRedReader == 0)) {
+ fRedReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else if ((fCurrentColor == "green") && (fGreenReader == 0)) {
+ fGreenReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else if ((fCurrentColor == "blue") && (fBlueReader == 0)) {
+ fBlueReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else if ((fCurrentColor == "white") && (fRedReader == 0) && (fGreenReader == 0) && (fBlueReader == 0)) {
+ fRedReader = new ZoneReader(zone, min, max);
+ fGreenReader = new ZoneReader(zone, min, max);
+ fBlueReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else {
+ std::cerr << "incorrect screencolor metadata : " << fCurrentColor << std::endl;
+ }
+ }
+ fCurrentColor = "";
+
+ fMetaData.push_back(fCurrentMetadata);
+ fCurrentMetadata.clear();
+ }
+
+ int getZoneIndex(std::vector<ZoneControl*>* table, int p, int val)
+ {
+ FAUSTFLOAT* zone = fZone[p];
+ for (size_t i = 0; i < table[val].size(); i++) {
+ if (zone == table[val][i]->getZone()) return int(i);
+ }
+ return -1;
+ }
+
+ void setConverter(std::vector<ZoneControl*>* table, int p, int val, int curve, double amin, double amid, double amax)
+ {
+ int id1 = getZoneIndex(table, p, 0);
+ int id2 = getZoneIndex(table, p, 1);
+ int id3 = getZoneIndex(table, p, 2);
+
+ // Deactivates everywhere..
+ if (id1 != -1) table[0][id1]->setActive(false);
+ if (id2 != -1) table[1][id2]->setActive(false);
+ if (id3 != -1) table[2][id3]->setActive(false);
+
+ if (val == -1) { // Means: no more mapping...
+ // So stay all deactivated...
+ } else {
+ int id4 = getZoneIndex(table, p, val);
+ if (id4 != -1) {
+ // Reactivate the one we edit...
+ table[val][id4]->setMappingValues(curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]);
+ table[val][id4]->setActive(true);
+ } else {
+ // Allocate a new CurveZoneControl which is 'active' by default
+ FAUSTFLOAT* zone = fZone[p];
+ table[val].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]));
+ }
+ }
+ }
+
+ void getConverter(std::vector<ZoneControl*>* table, int p, int& val, int& curve, double& amin, double& amid, double& amax)
+ {
+ int id1 = getZoneIndex(table, p, 0);
+ int id2 = getZoneIndex(table, p, 1);
+ int id3 = getZoneIndex(table, p, 2);
+
+ if (id1 != -1) {
+ val = 0;
+ curve = table[val][id1]->getCurve();
+ table[val][id1]->getMappingValues(amin, amid, amax);
+ } else if (id2 != -1) {
+ val = 1;
+ curve = table[val][id2]->getCurve();
+ table[val][id2]->getMappingValues(amin, amid, amax);
+ } else if (id3 != -1) {
+ val = 2;
+ curve = table[val][id3]->getCurve();
+ table[val][id3]->getMappingValues(amin, amid, amax);
+ } else {
+ val = -1; // No mapping
+ curve = 0;
+ amin = -100.;
+ amid = 0.;
+ amax = 100.;
+ }
+ }
+
+ public:
+
+ enum Type { kAcc = 0, kGyr = 1, kNoType };
+
+ APIUI() : fNumParameters(0), fHasScreenControl(false), fRedReader(0), fGreenReader(0), fBlueReader(0), fCurrentScale(kLin)
+ {}
+
+ virtual ~APIUI()
+ {
+ for (auto& it : fConversion) delete it;
+ for (int i = 0; i < 3; i++) {
+ for (auto& it : fAcc[i]) delete it;
+ for (auto& it : fGyr[i]) delete it;
+ }
+ delete fRedReader;
+ delete fGreenReader;
+ delete fBlueReader;
+ }
+
+ // -- widget's layouts
+
+ virtual void openTabBox(const char* label) { pushLabel(label); }
+ virtual void openHorizontalBox(const char* label) { pushLabel(label); }
+ virtual void openVerticalBox(const char* label) { pushLabel(label); }
+ virtual void closeBox() { popLabel(); }
+
+ // -- active widgets
+
+ virtual void addButton(const char* label, FAUSTFLOAT* zone)
+ {
+ addParameter(label, zone, 0, 0, 1, 1, kButton);
+ }
+
+ virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
+ {
+ addParameter(label, zone, 0, 0, 1, 1, kCheckButton);
+ }
+
+ virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+ {
+ addParameter(label, zone, init, min, max, step, kVSlider);
+ }
+
+ virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+ {
+ addParameter(label, zone, init, min, max, step, kHSlider);
+ }
+
+ virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+ {
+ addParameter(label, zone, init, min, max, step, kNumEntry);
+ }
+
+ // -- passive widgets
+
+ virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
+ {
+ addParameter(label, zone, min, min, max, (max-min)/1000.0, kHBargraph);
+ }
+
+ virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
+ {
+ addParameter(label, zone, min, min, max, (max-min)/1000.0, kVBargraph);
+ }
+
+ // -- soundfiles
+
+ virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) {}
+
+ // -- metadata declarations
+
+ virtual void declare(FAUSTFLOAT* zone, const char* key, const char* val)
+ {
+ // Keep metadata
+ fCurrentMetadata[key] = val;
+
+ if (strcmp(key, "scale") == 0) {
+ if (strcmp(val, "log") == 0) {
+ fCurrentScale = kLog;
+ } else if (strcmp(val, "exp") == 0) {
+ fCurrentScale = kExp;
+ } else {
+ fCurrentScale = kLin;
+ }
+ } else if (strcmp(key, "unit") == 0) {
+ fCurrentUnit = val;
+ } else if (strcmp(key, "acc") == 0) {
+ fCurrentAcc = val;
+ } else if (strcmp(key, "gyr") == 0) {
+ fCurrentGyr = val;
+ } else if (strcmp(key, "screencolor") == 0) {
+ fCurrentColor = val; // val = "red", "green", "blue" or "white"
+ } else if (strcmp(key, "tooltip") == 0) {
+ fCurrentTooltip = val;
+ }
+ }
+
+ virtual void declare(const char* key, const char* val)
+ {}
+
+ //-------------------------------------------------------------------------------
+ // Simple API part
+ //-------------------------------------------------------------------------------
+ int getParamsCount() { return fNumParameters; }
+ int getParamIndex(const char* path)
+ {
+ if (fPathMap.find(path) != fPathMap.end()) {
+ return fPathMap[path];
+ } else if (fLabelMap.find(path) != fLabelMap.end()) {
+ return fLabelMap[path];
+ } else {
+ return -1;
+ }
+ }
+ const char* getParamAddress(int p) { return fPaths[p].c_str(); }
+ const char* getParamLabel(int p) { return fLabels[p].c_str(); }
+ std::map<const char*, const char*> getMetadata(int p)
+ {
+ std::map<const char*, const char*> res;
+ std::map<std::string, std::string> metadata = fMetaData[p];
+ for (auto it : metadata) {
+ res[it.first.c_str()] = it.second.c_str();
+ }
+ return res;
+ }
+
+ const char* getMetadata(int p, const char* key)
+ {
+ return (fMetaData[p].find(key) != fMetaData[p].end()) ? fMetaData[p][key].c_str() : "";
+ }
+ FAUSTFLOAT getParamMin(int p) { return fMin[p]; }
+ FAUSTFLOAT getParamMax(int p) { return fMax[p]; }
+ FAUSTFLOAT getParamStep(int p) { return fStep[p]; }
+ FAUSTFLOAT getParamInit(int p) { return fInit[p]; }
+
+ FAUSTFLOAT* getParamZone(int p) { return fZone[p]; }
+ FAUSTFLOAT getParamValue(int p) { return *fZone[p]; }
+ void setParamValue(int p, FAUSTFLOAT v) { *fZone[p] = v; }
+
+ double getParamRatio(int p) { return fConversion[p]->faust2ui(*fZone[p]); }
+ void setParamRatio(int p, double r) { *fZone[p] = fConversion[p]->ui2faust(r); }
+
+ double value2ratio(int p, double r) { return fConversion[p]->faust2ui(r); }
+ double ratio2value(int p, double r) { return fConversion[p]->ui2faust(r); }
+
+ /**
+ * Return the control type (kAcc, kGyr, or -1) for a given parameter
+ *
+ * @param p - the UI parameter index
+ *
+ * @return the type
+ */
+ Type getParamType(int p)
+ {
+ if (p >= 0) {
+ if (getZoneIndex(fAcc, p, 0) != -1
+ || getZoneIndex(fAcc, p, 1) != -1
+ || getZoneIndex(fAcc, p, 2) != -1) {
+ return kAcc;
+ } else if (getZoneIndex(fGyr, p, 0) != -1
+ || getZoneIndex(fGyr, p, 1) != -1
+ || getZoneIndex(fGyr, p, 2) != -1) {
+ return kGyr;
+ }
+ }
+ return kNoType;
+ }
+
+ /**
+ * Return the Item type (kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry, kHBargraph, kVBargraph) for a given parameter
+ *
+ * @param p - the UI parameter index
+ *
+ * @return the Item type
+ */
+ ItemType getParamItemType(int p)
+ {
+ return fItemType[p];
+ }
+
+ /**
+ * Set a new value coming from an accelerometer, propagate it to all relevant FAUSTFLOAT* zones.
+ *
+ * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+ * @param value - the new value
+ *
+ */
+ void propagateAcc(int acc, double value)
+ {
+ for (size_t i = 0; i < fAcc[acc].size(); i++) {
+ fAcc[acc][i]->update(value);
+ }
+ }
+
+ /**
+ * Used to edit accelerometer curves and mapping. Set curve and related mapping for a given UI parameter.
+ *
+ * @param p - the UI parameter index
+ * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer (-1 means "no mapping")
+ * @param curve - between 0 and 3
+ * @param amin - mapping 'min' point
+ * @param amid - mapping 'middle' point
+ * @param amax - mapping 'max' point
+ *
+ */
+ void setAccConverter(int p, int acc, int curve, double amin, double amid, double amax)
+ {
+ setConverter(fAcc, p, acc, curve, amin, amid, amax);
+ }
+
+ /**
+ * Used to edit gyroscope curves and mapping. Set curve and related mapping for a given UI parameter.
+ *
+ * @param p - the UI parameter index
+ * @param acc - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope (-1 means "no mapping")
+ * @param curve - between 0 and 3
+ * @param amin - mapping 'min' point
+ * @param amid - mapping 'middle' point
+ * @param amax - mapping 'max' point
+ *
+ */
+ void setGyrConverter(int p, int gyr, int curve, double amin, double amid, double amax)
+ {
+ setConverter(fGyr, p, gyr, curve, amin, amid, amax);
+ }
+
+ /**
+ * Used to edit accelerometer curves and mapping. Get curve and related mapping for a given UI parameter.
+ *
+ * @param p - the UI parameter index
+ * @param acc - the acc value to be retrieved (-1 means "no mapping")
+ * @param curve - the curve value to be retrieved
+ * @param amin - the amin value to be retrieved
+ * @param amid - the amid value to be retrieved
+ * @param amax - the amax value to be retrieved
+ *
+ */
+ void getAccConverter(int p, int& acc, int& curve, double& amin, double& amid, double& amax)
+ {
+ getConverter(fAcc, p, acc, curve, amin, amid, amax);
+ }
+
+ /**
+ * Used to edit gyroscope curves and mapping. Get curve and related mapping for a given UI parameter.
+ *
+ * @param p - the UI parameter index
+ * @param gyr - the gyr value to be retrieved (-1 means "no mapping")
+ * @param curve - the curve value to be retrieved
+ * @param amin - the amin value to be retrieved
+ * @param amid - the amid value to be retrieved
+ * @param amax - the amax value to be retrieved
+ *
+ */
+ void getGyrConverter(int p, int& gyr, int& curve, double& amin, double& amid, double& amax)
+ {
+ getConverter(fGyr, p, gyr, curve, amin, amid, amax);
+ }
+
+ /**
+ * Set a new value coming from an gyroscope, propagate it to all relevant FAUSTFLOAT* zones.
+ *
+ * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
+ * @param value - the new value
+ *
+ */
+ void propagateGyr(int gyr, double value)
+ {
+ for (size_t i = 0; i < fGyr[gyr].size(); i++) {
+ fGyr[gyr][i]->update(value);
+ }
+ }
+
+ /**
+ * Get the number of FAUSTFLOAT* zones controlled with the accelerometer
+ *
+ * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+ * @return the number of zones
+ *
+ */
+ int getAccCount(int acc)
+ {
+ return (acc >= 0 && acc < 3) ? int(fAcc[acc].size()) : 0;
+ }
+
+ /**
+ * Get the number of FAUSTFLOAT* zones controlled with the gyroscope
+ *
+ * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
+ * @param the number of zones
+ *
+ */
+ int getGyrCount(int gyr)
+ {
+ return (gyr >= 0 && gyr < 3) ? int(fGyr[gyr].size()) : 0;
+ }
+
+ // getScreenColor() : -1 means no screen color control (no screencolor metadata found)
+ // otherwise return 0x00RRGGBB a ready to use color
+ int getScreenColor()
+ {
+ if (fHasScreenControl) {
+ int r = (fRedReader) ? fRedReader->getValue() : 0;
+ int g = (fGreenReader) ? fGreenReader->getValue() : 0;
+ int b = (fBlueReader) ? fBlueReader->getValue() : 0;
+ return (r<<16) | (g<<8) | b;
+ } else {
+ return -1;
+ }
+ }
+
+};
+
+#endif
+/************************** END APIUI.h **************************/
+
+// NOTE: "faust -scn name" changes the last line above to
+// #include <faust/name/name.h>
+
+//----------------------------------------------------------------------------
+// FAUST Generated Code
+//----------------------------------------------------------------------------
+
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+#include <algorithm>
+#include <cmath>
+#include <math.h>
+
+
+#ifndef FAUSTCLASS
+#define FAUSTCLASS freeverbdsp
+#endif
+
+#ifdef __APPLE__
+#define exp10f __exp10f
+#define exp10 __exp10
+#endif
+
+class freeverbdsp : public dsp {
+
+ private:
+
+ int fSampleRate;
+ float fConst0;
+ float fConst1;
+ FAUSTFLOAT fVslider0;
+ float fConst2;
+ FAUSTFLOAT fVslider1;
+ float fRec9[2];
+ FAUSTFLOAT fVslider2;
+ int IOTA;
+ float fVec0[8192];
+ int iConst3;
+ float fRec8[2];
+ float fRec11[2];
+ float fVec1[8192];
+ int iConst4;
+ float fRec10[2];
+ float fRec13[2];
+ float fVec2[8192];
+ int iConst5;
+ float fRec12[2];
+ float fRec15[2];
+ float fVec3[8192];
+ int iConst6;
+ float fRec14[2];
+ float fRec17[2];
+ float fVec4[8192];
+ int iConst7;
+ float fRec16[2];
+ float fRec19[2];
+ float fVec5[8192];
+ int iConst8;
+ float fRec18[2];
+ float fRec21[2];
+ float fVec6[8192];
+ int iConst9;
+ float fRec20[2];
+ float fRec23[2];
+ float fVec7[8192];
+ int iConst10;
+ float fRec22[2];
+ float fVec8[2048];
+ int iConst11;
+ int iConst12;
+ float fRec6[2];
+ float fVec9[2048];
+ int iConst13;
+ int iConst14;
+ float fRec4[2];
+ float fVec10[2048];
+ int iConst15;
+ int iConst16;
+ float fRec2[2];
+ float fVec11[1024];
+ int iConst17;
+ int iConst18;
+ float fRec0[2];
+ float fRec33[2];
+ float fVec12[8192];
+ float fConst19;
+ FAUSTFLOAT fVslider3;
+ float fRec32[2];
+ float fRec35[2];
+ float fVec13[8192];
+ float fRec34[2];
+ float fRec37[2];
+ float fVec14[8192];
+ float fRec36[2];
+ float fRec39[2];
+ float fVec15[8192];
+ float fRec38[2];
+ float fRec41[2];
+ float fVec16[8192];
+ float fRec40[2];
+ float fRec43[2];
+ float fVec17[8192];
+ float fRec42[2];
+ float fRec45[2];
+ float fVec18[8192];
+ float fRec44[2];
+ float fRec47[2];
+ float fVec19[8192];
+ float fRec46[2];
+ float fVec20[2048];
+ float fRec30[2];
+ float fVec21[2048];
+ float fRec28[2];
+ float fVec22[2048];
+ float fRec26[2];
+ float fVec23[2048];
+ float fRec24[2];
+
+ public:
+
+ void metadata(Meta* m) {
+ m->declare("author", "Romain Michon");
+ m->declare("delays.lib/name", "Faust Delay Library");
+ m->declare("delays.lib/version", "0.1");
+ m->declare("description", "Freeverb implementation in Faust, from the Faust Library's dm.freeverb_demo in demos.lib");
+ m->declare("filename", "freeverbdsp.dsp");
+ m->declare("filters.lib/allpass_comb:author", "Julius O. Smith III");
+ m->declare("filters.lib/allpass_comb:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+ m->declare("filters.lib/allpass_comb:license", "MIT-style STK-4.3 license");
+ m->declare("filters.lib/lowpass0_highpass1", "MIT-style STK-4.3 license");
+ m->declare("filters.lib/name", "Faust Filters Library");
+ m->declare("license", "LGPL");
+ m->declare("maths.lib/author", "GRAME");
+ m->declare("maths.lib/copyright", "GRAME");
+ m->declare("maths.lib/license", "LGPL with exception");
+ m->declare("maths.lib/name", "Faust Math Library");
+ m->declare("maths.lib/version", "2.3");
+ m->declare("name", "freeverb");
+ m->declare("platform.lib/name", "Generic Platform Library");
+ m->declare("platform.lib/version", "0.1");
+ m->declare("reverbs.lib/name", "Faust Reverb Library");
+ m->declare("reverbs.lib/version", "0.0");
+ m->declare("version", "0.0");
+ }
+
+ virtual int getNumInputs() {
+ return 2;
+ }
+ virtual int getNumOutputs() {
+ return 2;
+ }
+ virtual int getInputRate(int channel) {
+ int rate;
+ switch ((channel)) {
+ case 0: {
+ rate = 1;
+ break;
+ }
+ case 1: {
+ rate = 1;
+ break;
+ }
+ default: {
+ rate = -1;
+ break;
+ }
+ }
+ return rate;
+ }
+ virtual int getOutputRate(int channel) {
+ int rate;
+ switch ((channel)) {
+ case 0: {
+ rate = 1;
+ break;
+ }
+ case 1: {
+ rate = 1;
+ break;
+ }
+ default: {
+ rate = -1;
+ break;
+ }
+ }
+ return rate;
+ }
+
+ static void classInit(int sample_rate) {
+ }
+
+ virtual void instanceConstants(int sample_rate) {
+ fSampleRate = sample_rate;
+ fConst0 = std::min<float>(192000.0f, std::max<float>(1.0f, float(fSampleRate)));
+ fConst1 = (12348.0f / fConst0);
+ fConst2 = (17640.0f / fConst0);
+ iConst3 = int((0.0253061224f * fConst0));
+ iConst4 = int((0.0269387756f * fConst0));
+ iConst5 = int((0.0289569162f * fConst0));
+ iConst6 = int((0.0307482984f * fConst0));
+ iConst7 = int((0.0322448984f * fConst0));
+ iConst8 = int((0.033809524f * fConst0));
+ iConst9 = int((0.0353061222f * fConst0));
+ iConst10 = int((0.0366666652f * fConst0));
+ iConst11 = int((0.0126077095f * fConst0));
+ iConst12 = std::min<int>(1024, std::max<int>(0, (iConst11 + -1)));
+ iConst13 = int((0.00999999978f * fConst0));
+ iConst14 = std::min<int>(1024, std::max<int>(0, (iConst13 + -1)));
+ iConst15 = int((0.00773242628f * fConst0));
+ iConst16 = std::min<int>(1024, std::max<int>(0, (iConst15 + -1)));
+ iConst17 = int((0.00510204071f * fConst0));
+ iConst18 = std::min<int>(1024, std::max<int>(0, (iConst17 + -1)));
+ fConst19 = (0.00104308384f * fConst0);
+ }
+
+ virtual void instanceResetUserInterface() {
+ fVslider0 = FAUSTFLOAT(0.10000000000000001f);
+ fVslider1 = FAUSTFLOAT(0.5f);
+ fVslider2 = FAUSTFLOAT(0.10000000000000001f);
+ fVslider3 = FAUSTFLOAT(0.5f);
+ }
+
+ virtual void instanceClear() {
+ for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) {
+ fRec9[l0] = 0.0f;
+ }
+ IOTA = 0;
+ for (int l1 = 0; (l1 < 8192); l1 = (l1 + 1)) {
+ fVec0[l1] = 0.0f;
+ }
+ for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) {
+ fRec8[l2] = 0.0f;
+ }
+ for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) {
+ fRec11[l3] = 0.0f;
+ }
+ for (int l4 = 0; (l4 < 8192); l4 = (l4 + 1)) {
+ fVec1[l4] = 0.0f;
+ }
+ for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) {
+ fRec10[l5] = 0.0f;
+ }
+ for (int l6 = 0; (l6 < 2); l6 = (l6 + 1)) {
+ fRec13[l6] = 0.0f;
+ }
+ for (int l7 = 0; (l7 < 8192); l7 = (l7 + 1)) {
+ fVec2[l7] = 0.0f;
+ }
+ for (int l8 = 0; (l8 < 2); l8 = (l8 + 1)) {
+ fRec12[l8] = 0.0f;
+ }
+ for (int l9 = 0; (l9 < 2); l9 = (l9 + 1)) {
+ fRec15[l9] = 0.0f;
+ }
+ for (int l10 = 0; (l10 < 8192); l10 = (l10 + 1)) {
+ fVec3[l10] = 0.0f;
+ }
+ for (int l11 = 0; (l11 < 2); l11 = (l11 + 1)) {
+ fRec14[l11] = 0.0f;
+ }
+ for (int l12 = 0; (l12 < 2); l12 = (l12 + 1)) {
+ fRec17[l12] = 0.0f;
+ }
+ for (int l13 = 0; (l13 < 8192); l13 = (l13 + 1)) {
+ fVec4[l13] = 0.0f;
+ }
+ for (int l14 = 0; (l14 < 2); l14 = (l14 + 1)) {
+ fRec16[l14] = 0.0f;
+ }
+ for (int l15 = 0; (l15 < 2); l15 = (l15 + 1)) {
+ fRec19[l15] = 0.0f;
+ }
+ for (int l16 = 0; (l16 < 8192); l16 = (l16 + 1)) {
+ fVec5[l16] = 0.0f;
+ }
+ for (int l17 = 0; (l17 < 2); l17 = (l17 + 1)) {
+ fRec18[l17] = 0.0f;
+ }
+ for (int l18 = 0; (l18 < 2); l18 = (l18 + 1)) {
+ fRec21[l18] = 0.0f;
+ }
+ for (int l19 = 0; (l19 < 8192); l19 = (l19 + 1)) {
+ fVec6[l19] = 0.0f;
+ }
+ for (int l20 = 0; (l20 < 2); l20 = (l20 + 1)) {
+ fRec20[l20] = 0.0f;
+ }
+ for (int l21 = 0; (l21 < 2); l21 = (l21 + 1)) {
+ fRec23[l21] = 0.0f;
+ }
+ for (int l22 = 0; (l22 < 8192); l22 = (l22 + 1)) {
+ fVec7[l22] = 0.0f;
+ }
+ for (int l23 = 0; (l23 < 2); l23 = (l23 + 1)) {
+ fRec22[l23] = 0.0f;
+ }
+ for (int l24 = 0; (l24 < 2048); l24 = (l24 + 1)) {
+ fVec8[l24] = 0.0f;
+ }
+ for (int l25 = 0; (l25 < 2); l25 = (l25 + 1)) {
+ fRec6[l25] = 0.0f;
+ }
+ for (int l26 = 0; (l26 < 2048); l26 = (l26 + 1)) {
+ fVec9[l26] = 0.0f;
+ }
+ for (int l27 = 0; (l27 < 2); l27 = (l27 + 1)) {
+ fRec4[l27] = 0.0f;
+ }
+ for (int l28 = 0; (l28 < 2048); l28 = (l28 + 1)) {
+ fVec10[l28] = 0.0f;
+ }
+ for (int l29 = 0; (l29 < 2); l29 = (l29 + 1)) {
+ fRec2[l29] = 0.0f;
+ }
+ for (int l30 = 0; (l30 < 1024); l30 = (l30 + 1)) {
+ fVec11[l30] = 0.0f;
+ }
+ for (int l31 = 0; (l31 < 2); l31 = (l31 + 1)) {
+ fRec0[l31] = 0.0f;
+ }
+ for (int l32 = 0; (l32 < 2); l32 = (l32 + 1)) {
+ fRec33[l32] = 0.0f;
+ }
+ for (int l33 = 0; (l33 < 8192); l33 = (l33 + 1)) {
+ fVec12[l33] = 0.0f;
+ }
+ for (int l34 = 0; (l34 < 2); l34 = (l34 + 1)) {
+ fRec32[l34] = 0.0f;
+ }
+ for (int l35 = 0; (l35 < 2); l35 = (l35 + 1)) {
+ fRec35[l35] = 0.0f;
+ }
+ for (int l36 = 0; (l36 < 8192); l36 = (l36 + 1)) {
+ fVec13[l36] = 0.0f;
+ }
+ for (int l37 = 0; (l37 < 2); l37 = (l37 + 1)) {
+ fRec34[l37] = 0.0f;
+ }
+ for (int l38 = 0; (l38 < 2); l38 = (l38 + 1)) {
+ fRec37[l38] = 0.0f;
+ }
+ for (int l39 = 0; (l39 < 8192); l39 = (l39 + 1)) {
+ fVec14[l39] = 0.0f;
+ }
+ for (int l40 = 0; (l40 < 2); l40 = (l40 + 1)) {
+ fRec36[l40] = 0.0f;
+ }
+ for (int l41 = 0; (l41 < 2); l41 = (l41 + 1)) {
+ fRec39[l41] = 0.0f;
+ }
+ for (int l42 = 0; (l42 < 8192); l42 = (l42 + 1)) {
+ fVec15[l42] = 0.0f;
+ }
+ for (int l43 = 0; (l43 < 2); l43 = (l43 + 1)) {
+ fRec38[l43] = 0.0f;
+ }
+ for (int l44 = 0; (l44 < 2); l44 = (l44 + 1)) {
+ fRec41[l44] = 0.0f;
+ }
+ for (int l45 = 0; (l45 < 8192); l45 = (l45 + 1)) {
+ fVec16[l45] = 0.0f;
+ }
+ for (int l46 = 0; (l46 < 2); l46 = (l46 + 1)) {
+ fRec40[l46] = 0.0f;
+ }
+ for (int l47 = 0; (l47 < 2); l47 = (l47 + 1)) {
+ fRec43[l47] = 0.0f;
+ }
+ for (int l48 = 0; (l48 < 8192); l48 = (l48 + 1)) {
+ fVec17[l48] = 0.0f;
+ }
+ for (int l49 = 0; (l49 < 2); l49 = (l49 + 1)) {
+ fRec42[l49] = 0.0f;
+ }
+ for (int l50 = 0; (l50 < 2); l50 = (l50 + 1)) {
+ fRec45[l50] = 0.0f;
+ }
+ for (int l51 = 0; (l51 < 8192); l51 = (l51 + 1)) {
+ fVec18[l51] = 0.0f;
+ }
+ for (int l52 = 0; (l52 < 2); l52 = (l52 + 1)) {
+ fRec44[l52] = 0.0f;
+ }
+ for (int l53 = 0; (l53 < 2); l53 = (l53 + 1)) {
+ fRec47[l53] = 0.0f;
+ }
+ for (int l54 = 0; (l54 < 8192); l54 = (l54 + 1)) {
+ fVec19[l54] = 0.0f;
+ }
+ for (int l55 = 0; (l55 < 2); l55 = (l55 + 1)) {
+ fRec46[l55] = 0.0f;
+ }
+ for (int l56 = 0; (l56 < 2048); l56 = (l56 + 1)) {
+ fVec20[l56] = 0.0f;
+ }
+ for (int l57 = 0; (l57 < 2); l57 = (l57 + 1)) {
+ fRec30[l57] = 0.0f;
+ }
+ for (int l58 = 0; (l58 < 2048); l58 = (l58 + 1)) {
+ fVec21[l58] = 0.0f;
+ }
+ for (int l59 = 0; (l59 < 2); l59 = (l59 + 1)) {
+ fRec28[l59] = 0.0f;
+ }
+ for (int l60 = 0; (l60 < 2048); l60 = (l60 + 1)) {
+ fVec22[l60] = 0.0f;
+ }
+ for (int l61 = 0; (l61 < 2); l61 = (l61 + 1)) {
+ fRec26[l61] = 0.0f;
+ }
+ for (int l62 = 0; (l62 < 2048); l62 = (l62 + 1)) {
+ fVec23[l62] = 0.0f;
+ }
+ for (int l63 = 0; (l63 < 2); l63 = (l63 + 1)) {
+ fRec24[l63] = 0.0f;
+ }
+ }
+
+ virtual void init(int sample_rate) {
+ classInit(sample_rate);
+ instanceInit(sample_rate);
+ }
+ virtual void instanceInit(int sample_rate) {
+ instanceConstants(sample_rate);
+ instanceResetUserInterface();
+ instanceClear();
+ }
+
+ virtual freeverbdsp* clone() {
+ return new freeverbdsp();
+ }
+
+ virtual int getSampleRate() {
+ return fSampleRate;
+ }
+
+ virtual void buildUserInterface(UI* ui_interface) {
+ ui_interface->openHorizontalBox("Freeverb");
+ ui_interface->declare(0, "0", "");
+ ui_interface->openVerticalBox("0x00");
+ ui_interface->declare(&fVslider1, "0", "");
+ ui_interface->declare(&fVslider1, "style", "knob");
+ ui_interface->declare(&fVslider1, "tooltip", "Somehow control the density of the reverb.");
+ ui_interface->addVerticalSlider("Damp", &fVslider1, 0.5f, 0.0f, 1.0f, 0.0250000004f);
+ ui_interface->declare(&fVslider0, "1", "");
+ ui_interface->declare(&fVslider0, "style", "knob");
+ ui_interface->declare(&fVslider0, "tooltip", "The room size between 0 and 1 with 1 for the largest room.");
+ ui_interface->addVerticalSlider("RoomSize", &fVslider0, 0.100000001f, 0.0f, 1.0f, 0.0250000004f);
+ ui_interface->declare(&fVslider3, "2", "");
+ ui_interface->declare(&fVslider3, "style", "knob");
+ ui_interface->declare(&fVslider3, "tooltip", "Spatial spread between 0 and 1 with 1 for maximum spread.");
+ ui_interface->addVerticalSlider("Stereo Spread", &fVslider3, 0.5f, 0.0f, 1.0f, 0.00999999978f);
+ ui_interface->closeBox();
+ ui_interface->declare(&fVslider2, "1", "");
+ ui_interface->declare(&fVslider2, "tooltip", "The amount of reverb applied to the signal between 0 and 1 with 1 for the maximum amount of reverb.");
+ ui_interface->addVerticalSlider("Wet", &fVslider2, 0.100000001f, 0.0f, 1.0f, 0.0250000004f);
+ ui_interface->closeBox();
+ }
+
+ virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
+ FAUSTFLOAT* input0 = inputs[0];
+ FAUSTFLOAT* input1 = inputs[1];
+ FAUSTFLOAT* output0 = outputs[0];
+ FAUSTFLOAT* output1 = outputs[1];
+ float fSlow0 = ((fConst1 * float(fVslider0)) + 0.699999988f);
+ float fSlow1 = (fConst2 * float(fVslider1));
+ float fSlow2 = (1.0f - fSlow1);
+ float fSlow3 = float(fVslider2);
+ float fSlow4 = (0.100000001f * fSlow3);
+ float fSlow5 = (1.0f - fSlow3);
+ int iSlow6 = int((fConst19 * float(fVslider3)));
+ int iSlow7 = (iConst3 + iSlow6);
+ int iSlow8 = (iConst4 + iSlow6);
+ int iSlow9 = (iConst5 + iSlow6);
+ int iSlow10 = (iConst6 + iSlow6);
+ int iSlow11 = (iConst7 + iSlow6);
+ int iSlow12 = (iConst8 + iSlow6);
+ int iSlow13 = (iConst9 + iSlow6);
+ int iSlow14 = (iConst10 + iSlow6);
+ int iSlow15 = (iSlow6 + -1);
+ int iSlow16 = std::min<int>(1024, std::max<int>(0, (iConst11 + iSlow15)));
+ int iSlow17 = std::min<int>(1024, std::max<int>(0, (iConst13 + iSlow15)));
+ int iSlow18 = std::min<int>(1024, std::max<int>(0, (iConst15 + iSlow15)));
+ int iSlow19 = std::min<int>(1024, std::max<int>(0, (iConst17 + iSlow15)));
+ for (int i = 0; (i < count); i = (i + 1)) {
+ float fTemp0 = float(input0[i]);
+ float fTemp1 = float(input1[i]);
+ fRec9[0] = ((fSlow1 * fRec9[1]) + (fSlow2 * fRec8[1]));
+ float fTemp2 = (fSlow4 * (fTemp0 + fTemp1));
+ fVec0[(IOTA & 8191)] = ((fSlow0 * fRec9[0]) + fTemp2);
+ fRec8[0] = fVec0[((IOTA - iConst3) & 8191)];
+ fRec11[0] = ((fSlow1 * fRec11[1]) + (fSlow2 * fRec10[1]));
+ fVec1[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec11[0]));
+ fRec10[0] = fVec1[((IOTA - iConst4) & 8191)];
+ fRec13[0] = ((fSlow1 * fRec13[1]) + (fSlow2 * fRec12[1]));
+ fVec2[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec13[0]));
+ fRec12[0] = fVec2[((IOTA - iConst5) & 8191)];
+ fRec15[0] = ((fSlow1 * fRec15[1]) + (fSlow2 * fRec14[1]));
+ fVec3[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec15[0]));
+ fRec14[0] = fVec3[((IOTA - iConst6) & 8191)];
+ fRec17[0] = ((fSlow1 * fRec17[1]) + (fSlow2 * fRec16[1]));
+ fVec4[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec17[0]));
+ fRec16[0] = fVec4[((IOTA - iConst7) & 8191)];
+ fRec19[0] = ((fSlow1 * fRec19[1]) + (fSlow2 * fRec18[1]));
+ fVec5[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec19[0]));
+ fRec18[0] = fVec5[((IOTA - iConst8) & 8191)];
+ fRec21[0] = ((fSlow1 * fRec21[1]) + (fSlow2 * fRec20[1]));
+ fVec6[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec21[0]));
+ fRec20[0] = fVec6[((IOTA - iConst9) & 8191)];
+ fRec23[0] = ((fSlow1 * fRec23[1]) + (fSlow2 * fRec22[1]));
+ fVec7[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec23[0]));
+ fRec22[0] = fVec7[((IOTA - iConst10) & 8191)];
+ float fTemp3 = ((((((((fRec8[0] + fRec10[0]) + fRec12[0]) + fRec14[0]) + fRec16[0]) + fRec18[0]) + fRec20[0]) + fRec22[0]) + (0.5f * fRec6[1]));
+ fVec8[(IOTA & 2047)] = fTemp3;
+ fRec6[0] = fVec8[((IOTA - iConst12) & 2047)];
+ float fRec7 = (0.0f - (0.5f * fTemp3));
+ float fTemp4 = (fRec6[1] + (fRec7 + (0.5f * fRec4[1])));
+ fVec9[(IOTA & 2047)] = fTemp4;
+ fRec4[0] = fVec9[((IOTA - iConst14) & 2047)];
+ float fRec5 = (0.0f - (0.5f * fTemp4));
+ float fTemp5 = (fRec4[1] + (fRec5 + (0.5f * fRec2[1])));
+ fVec10[(IOTA & 2047)] = fTemp5;
+ fRec2[0] = fVec10[((IOTA - iConst16) & 2047)];
+ float fRec3 = (0.0f - (0.5f * fTemp5));
+ float fTemp6 = (fRec2[1] + (fRec3 + (0.5f * fRec0[1])));
+ fVec11[(IOTA & 1023)] = fTemp6;
+ fRec0[0] = fVec11[((IOTA - iConst18) & 1023)];
+ float fRec1 = (0.0f - (0.5f * fTemp6));
+ output0[i] = FAUSTFLOAT(((fRec1 + fRec0[1]) + (fSlow5 * fTemp0)));
+ fRec33[0] = ((fSlow1 * fRec33[1]) + (fSlow2 * fRec32[1]));
+ fVec12[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec33[0]));
+ fRec32[0] = fVec12[((IOTA - iSlow7) & 8191)];
+ fRec35[0] = ((fSlow1 * fRec35[1]) + (fSlow2 * fRec34[1]));
+ fVec13[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec35[0]));
+ fRec34[0] = fVec13[((IOTA - iSlow8) & 8191)];
+ fRec37[0] = ((fSlow1 * fRec37[1]) + (fSlow2 * fRec36[1]));
+ fVec14[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec37[0]));
+ fRec36[0] = fVec14[((IOTA - iSlow9) & 8191)];
+ fRec39[0] = ((fSlow1 * fRec39[1]) + (fSlow2 * fRec38[1]));
+ fVec15[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec39[0]));
+ fRec38[0] = fVec15[((IOTA - iSlow10) & 8191)];
+ fRec41[0] = ((fSlow1 * fRec41[1]) + (fSlow2 * fRec40[1]));
+ fVec16[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec41[0]));
+ fRec40[0] = fVec16[((IOTA - iSlow11) & 8191)];
+ fRec43[0] = ((fSlow1 * fRec43[1]) + (fSlow2 * fRec42[1]));
+ fVec17[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec43[0]));
+ fRec42[0] = fVec17[((IOTA - iSlow12) & 8191)];
+ fRec45[0] = ((fSlow1 * fRec45[1]) + (fSlow2 * fRec44[1]));
+ fVec18[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec45[0]));
+ fRec44[0] = fVec18[((IOTA - iSlow13) & 8191)];
+ fRec47[0] = ((fSlow1 * fRec47[1]) + (fSlow2 * fRec46[1]));
+ fVec19[(IOTA & 8191)] = (fTemp2 + (fSlow0 * fRec47[0]));
+ fRec46[0] = fVec19[((IOTA - iSlow14) & 8191)];
+ float fTemp7 = ((((((((fRec32[0] + fRec34[0]) + fRec36[0]) + fRec38[0]) + fRec40[0]) + fRec42[0]) + fRec44[0]) + fRec46[0]) + (0.5f * fRec30[1]));
+ fVec20[(IOTA & 2047)] = fTemp7;
+ fRec30[0] = fVec20[((IOTA - iSlow16) & 2047)];
+ float fRec31 = (0.0f - (0.5f * fTemp7));
+ float fTemp8 = (fRec30[1] + (fRec31 + (0.5f * fRec28[1])));
+ fVec21[(IOTA & 2047)] = fTemp8;
+ fRec28[0] = fVec21[((IOTA - iSlow17) & 2047)];
+ float fRec29 = (0.0f - (0.5f * fTemp8));
+ float fTemp9 = (fRec28[1] + (fRec29 + (0.5f * fRec26[1])));
+ fVec22[(IOTA & 2047)] = fTemp9;
+ fRec26[0] = fVec22[((IOTA - iSlow18) & 2047)];
+ float fRec27 = (0.0f - (0.5f * fTemp9));
+ float fTemp10 = (fRec26[1] + (fRec27 + (0.5f * fRec24[1])));
+ fVec23[(IOTA & 2047)] = fTemp10;
+ fRec24[0] = fVec23[((IOTA - iSlow19) & 2047)];
+ float fRec25 = (0.0f - (0.5f * fTemp10));
+ output1[i] = FAUSTFLOAT(((fRec25 + fRec24[1]) + (fSlow5 * fTemp1)));
+ fRec9[1] = fRec9[0];
+ IOTA = (IOTA + 1);
+ fRec8[1] = fRec8[0];
+ fRec11[1] = fRec11[0];
+ fRec10[1] = fRec10[0];
+ fRec13[1] = fRec13[0];
+ fRec12[1] = fRec12[0];
+ fRec15[1] = fRec15[0];
+ fRec14[1] = fRec14[0];
+ fRec17[1] = fRec17[0];
+ fRec16[1] = fRec16[0];
+ fRec19[1] = fRec19[0];
+ fRec18[1] = fRec18[0];
+ fRec21[1] = fRec21[0];
+ fRec20[1] = fRec20[0];
+ fRec23[1] = fRec23[0];
+ fRec22[1] = fRec22[0];
+ fRec6[1] = fRec6[0];
+ fRec4[1] = fRec4[0];
+ fRec2[1] = fRec2[0];
+ fRec0[1] = fRec0[0];
+ fRec33[1] = fRec33[0];
+ fRec32[1] = fRec32[0];
+ fRec35[1] = fRec35[0];
+ fRec34[1] = fRec34[0];
+ fRec37[1] = fRec37[0];
+ fRec36[1] = fRec36[0];
+ fRec39[1] = fRec39[0];
+ fRec38[1] = fRec38[0];
+ fRec41[1] = fRec41[0];
+ fRec40[1] = fRec40[0];
+ fRec43[1] = fRec43[0];
+ fRec42[1] = fRec42[0];
+ fRec45[1] = fRec45[0];
+ fRec44[1] = fRec44[0];
+ fRec47[1] = fRec47[0];
+ fRec46[1] = fRec46[0];
+ fRec30[1] = fRec30[0];
+ fRec28[1] = fRec28[0];
+ fRec26[1] = fRec26[0];
+ fRec24[1] = fRec24[0];
+ }
+ }
+
+};
+
+#endif
diff --git a/src/freeverbmonodsp.h b/src/freeverbmonodsp.h
new file mode 100644
index 0000000..5de618e
--- /dev/null
+++ b/src/freeverbmonodsp.h
@@ -0,0 +1,2154 @@
+/* ------------------------------------------------------------
+name: "freeverbmonodsp"
+Code generated with Faust 2.28.6 (https://faust.grame.fr)
+Compilation options: -lang cpp -inpl -scal -ftz 0
+------------------------------------------------------------ */
+
+#ifndef __freeverbmonodsp_H__
+#define __freeverbmonodsp_H__
+
+// NOTE: ANY INCLUDE-GUARD HERE MUST BE DERIVED FROM THE CLASS NAME
+//
+// faust2header.cpp - FAUST Architecture File
+// This is a simple variation of matlabplot.cpp in the Faust distribution
+// aimed at creating a simple C++ header file (.h) containing a Faust DSP.
+// See the Makefile for how to use it.
+
+/************************** BEGIN dsp.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __dsp__
+#define __dsp__
+
+#include <string>
+#include <vector>
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+struct UI;
+struct Meta;
+
+/**
+ * DSP memory manager.
+ */
+
+struct dsp_memory_manager {
+
+ virtual ~dsp_memory_manager() {}
+
+ virtual void* allocate(size_t size) = 0;
+ virtual void destroy(void* ptr) = 0;
+
+};
+
+/**
+* Signal processor definition.
+*/
+
+class dsp {
+
+ public:
+
+ dsp() {}
+ virtual ~dsp() {}
+
+ /* Return instance number of audio inputs */
+ virtual int getNumInputs() = 0;
+
+ /* Return instance number of audio outputs */
+ virtual int getNumOutputs() = 0;
+
+ /**
+ * Trigger the ui_interface parameter with instance specific calls
+ * to 'openTabBox', 'addButton', 'addVerticalSlider'... in order to build the UI.
+ *
+ * @param ui_interface - the user interface builder
+ */
+ virtual void buildUserInterface(UI* ui_interface) = 0;
+
+ /* Returns the sample rate currently used by the instance */
+ virtual int getSampleRate() = 0;
+
+ /**
+ * Global init, calls the following methods:
+ * - static class 'classInit': static tables initialization
+ * - 'instanceInit': constants and instance state initialization
+ *
+ * @param sample_rate - the sampling rate in Hertz
+ */
+ virtual void init(int sample_rate) = 0;
+
+ /**
+ * Init instance state
+ *
+ * @param sample_rate - the sampling rate in Hertz
+ */
+ virtual void instanceInit(int sample_rate) = 0;
+
+ /**
+ * Init instance constant state
+ *
+ * @param sample_rate - the sampling rate in Hertz
+ */
+ virtual void instanceConstants(int sample_rate) = 0;
+
+ /* Init default control parameters values */
+ virtual void instanceResetUserInterface() = 0;
+
+ /* Init instance state (delay lines...) */
+ virtual void instanceClear() = 0;
+
+ /**
+ * Return a clone of the instance.
+ *
+ * @return a copy of the instance on success, otherwise a null pointer.
+ */
+ virtual dsp* clone() = 0;
+
+ /**
+ * Trigger the Meta* parameter with instance specific calls to 'declare' (key, value) metadata.
+ *
+ * @param m - the Meta* meta user
+ */
+ virtual void metadata(Meta* m) = 0;
+
+ /**
+ * DSP instance computation, to be called with successive in/out audio buffers.
+ *
+ * @param count - the number of frames to compute
+ * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
+ * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
+ *
+ */
+ virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) = 0;
+
+ /**
+ * DSP instance computation: alternative method to be used by subclasses.
+ *
+ * @param date_usec - the timestamp in microsec given by audio driver.
+ * @param count - the number of frames to compute
+ * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
+ * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
+ *
+ */
+ virtual void compute(double /*date_usec*/, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { compute(count, inputs, outputs); }
+
+};
+
+/**
+ * Generic DSP decorator.
+ */
+
+class decorator_dsp : public dsp {
+
+ protected:
+
+ dsp* fDSP;
+
+ public:
+
+ decorator_dsp(dsp* dsp = nullptr):fDSP(dsp) {}
+ virtual ~decorator_dsp() { delete fDSP; }
+
+ virtual int getNumInputs() { return fDSP->getNumInputs(); }
+ virtual int getNumOutputs() { return fDSP->getNumOutputs(); }
+ virtual void buildUserInterface(UI* ui_interface) { fDSP->buildUserInterface(ui_interface); }
+ virtual int getSampleRate() { return fDSP->getSampleRate(); }
+ virtual void init(int sample_rate) { fDSP->init(sample_rate); }
+ virtual void instanceInit(int sample_rate) { fDSP->instanceInit(sample_rate); }
+ virtual void instanceConstants(int sample_rate) { fDSP->instanceConstants(sample_rate); }
+ virtual void instanceResetUserInterface() { fDSP->instanceResetUserInterface(); }
+ virtual void instanceClear() { fDSP->instanceClear(); }
+ virtual decorator_dsp* clone() { return new decorator_dsp(fDSP->clone()); }
+ virtual void metadata(Meta* m) { fDSP->metadata(m); }
+ // Beware: subclasses usually have to overload the two 'compute' methods
+ virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(count, inputs, outputs); }
+ virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(date_usec, count, inputs, outputs); }
+
+};
+
+/**
+ * DSP factory class.
+ */
+
+class dsp_factory {
+
+ protected:
+
+ // So that to force sub-classes to use deleteDSPFactory(dsp_factory* factory);
+ virtual ~dsp_factory() {}
+
+ public:
+
+ virtual std::string getName() = 0;
+ virtual std::string getSHAKey() = 0;
+ virtual std::string getDSPCode() = 0;
+ virtual std::string getCompileOptions() = 0;
+ virtual std::vector<std::string> getLibraryList() = 0;
+ virtual std::vector<std::string> getIncludePathnames() = 0;
+
+ virtual dsp* createDSPInstance() = 0;
+
+ virtual void setMemoryManager(dsp_memory_manager* manager) = 0;
+ virtual dsp_memory_manager* getMemoryManager() = 0;
+
+};
+
+/**
+ * On Intel set FZ (Flush to Zero) and DAZ (Denormals Are Zero)
+ * flags to avoid costly denormals.
+ */
+
+#ifdef __SSE__
+ #include <xmmintrin.h>
+ #ifdef __SSE2__
+ #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
+ #else
+ #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
+ #endif
+#else
+ #define AVOIDDENORMALS
+#endif
+
+#endif
+/************************** END dsp.h **************************/
+
+/************************** BEGIN APIUI.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef API_UI_H
+#define API_UI_H
+
+#include <sstream>
+#include <string>
+#include <vector>
+#include <iostream>
+#include <map>
+
+/************************** BEGIN meta.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __meta__
+#define __meta__
+
+struct Meta
+{
+ virtual ~Meta() {};
+ virtual void declare(const char* key, const char* value) = 0;
+
+};
+
+#endif
+/************************** END meta.h **************************/
+/************************** BEGIN UI.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2020 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __UI_H__
+#define __UI_H__
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+/*******************************************************************************
+ * UI : Faust DSP User Interface
+ * User Interface as expected by the buildUserInterface() method of a DSP.
+ * This abstract class contains only the method that the Faust compiler can
+ * generate to describe a DSP user interface.
+ ******************************************************************************/
+
+struct Soundfile;
+
+template <typename REAL>
+struct UIReal
+{
+ UIReal() {}
+ virtual ~UIReal() {}
+
+ // -- widget's layouts
+
+ virtual void openTabBox(const char* label) = 0;
+ virtual void openHorizontalBox(const char* label) = 0;
+ virtual void openVerticalBox(const char* label) = 0;
+ virtual void closeBox() = 0;
+
+ // -- active widgets
+
+ virtual void addButton(const char* label, REAL* zone) = 0;
+ virtual void addCheckButton(const char* label, REAL* zone) = 0;
+ virtual void addVerticalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
+ virtual void addHorizontalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
+ virtual void addNumEntry(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
+
+ // -- passive widgets
+
+ virtual void addHorizontalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
+ virtual void addVerticalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
+
+ // -- soundfiles
+
+ virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) = 0;
+
+ // -- metadata declarations
+
+ virtual void declare(REAL* zone, const char* key, const char* val) {}
+};
+
+struct UI : public UIReal<FAUSTFLOAT>
+{
+ UI() {}
+ virtual ~UI() {}
+};
+
+#endif
+/************************** END UI.h **************************/
+/************************** BEGIN PathBuilder.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef FAUST_PATHBUILDER_H
+#define FAUST_PATHBUILDER_H
+
+#include <vector>
+#include <string>
+#include <algorithm>
+
+/*******************************************************************************
+ * PathBuilder : Faust User Interface
+ * Helper class to build complete hierarchical path for UI items.
+ ******************************************************************************/
+
+class PathBuilder
+{
+
+ protected:
+
+ std::vector<std::string> fControlsLevel;
+
+ public:
+
+ PathBuilder() {}
+ virtual ~PathBuilder() {}
+
+ std::string buildPath(const std::string& label)
+ {
+ std::string res = "/";
+ for (size_t i = 0; i < fControlsLevel.size(); i++) {
+ res += fControlsLevel[i];
+ res += "/";
+ }
+ res += label;
+ std::replace(res.begin(), res.end(), ' ', '_');
+ return res;
+ }
+
+ std::string buildLabel(std::string label)
+ {
+ std::replace(label.begin(), label.end(), ' ', '_');
+ return label;
+ }
+
+ void pushLabel(const std::string& label) { fControlsLevel.push_back(label); }
+ void popLabel() { fControlsLevel.pop_back(); }
+
+};
+
+#endif // FAUST_PATHBUILDER_H
+/************************** END PathBuilder.h **************************/
+/************************** BEGIN ValueConverter.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __ValueConverter__
+#define __ValueConverter__
+
+/***************************************************************************************
+ ValueConverter.h
+ (GRAME, Copyright 2015-2019)
+
+Set of conversion objects used to map user interface values (for example a gui slider
+delivering values between 0 and 1) to faust values (for example a vslider between
+20 and 20000) using a log scale.
+
+-- Utilities
+
+Range(lo,hi) : clip a value x between lo and hi
+Interpolator(lo,hi,v1,v2) : Maps a value x between lo and hi to a value y between v1 and v2
+Interpolator3pt(lo,mi,hi,v1,vm,v2) : Map values between lo mid hi to values between v1 vm v2
+
+-- Value Converters
+
+ValueConverter::ui2faust(x)
+ValueConverter::faust2ui(x)
+
+-- ValueConverters used for sliders depending of the scale
+
+LinearValueConverter(umin, umax, fmin, fmax)
+LinearValueConverter2(lo, mi, hi, v1, vm, v2) using 2 segments
+LogValueConverter(umin, umax, fmin, fmax)
+ExpValueConverter(umin, umax, fmin, fmax)
+
+-- ValueConverters used for accelerometers based on 3 points
+
+AccUpConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 0
+AccDownConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 1
+AccUpDownConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 2
+AccDownUpConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 3
+
+-- lists of ZoneControl are used to implement accelerometers metadata for each axes
+
+ZoneControl(zone, valueConverter) : a zone with an accelerometer data converter
+
+-- ZoneReader are used to implement screencolor metadata
+
+ZoneReader(zone, valueConverter) : a zone with a data converter
+
+****************************************************************************************/
+
+#include <float.h>
+#include <algorithm> // std::max
+#include <cmath>
+#include <vector>
+#include <assert.h>
+
+//--------------------------------------------------------------------------------------
+// Interpolator(lo,hi,v1,v2)
+// Maps a value x between lo and hi to a value y between v1 and v2
+// y = v1 + (x-lo)/(hi-lo)*(v2-v1)
+// y = v1 + (x-lo) * coef with coef = (v2-v1)/(hi-lo)
+// y = v1 + x*coef - lo*coef
+// y = v1 - lo*coef + x*coef
+// y = offset + x*coef with offset = v1 - lo*coef
+//--------------------------------------------------------------------------------------
+class Interpolator
+{
+ private:
+
+ //--------------------------------------------------------------------------------------
+ // Range(lo,hi) clip a value between lo and hi
+ //--------------------------------------------------------------------------------------
+ struct Range
+ {
+ double fLo;
+ double fHi;
+
+ Range(double x, double y) : fLo(std::min<double>(x,y)), fHi(std::max<double>(x,y)) {}
+ double operator()(double x) { return (x<fLo) ? fLo : (x>fHi) ? fHi : x; }
+ };
+
+
+ Range fRange;
+ double fCoef;
+ double fOffset;
+
+ public:
+
+ Interpolator(double lo, double hi, double v1, double v2) : fRange(lo,hi)
+ {
+ if (hi != lo) {
+ // regular case
+ fCoef = (v2-v1)/(hi-lo);
+ fOffset = v1 - lo*fCoef;
+ } else {
+ // degenerate case, avoids division by zero
+ fCoef = 0;
+ fOffset = (v1+v2)/2;
+ }
+ }
+ double operator()(double v)
+ {
+ double x = fRange(v);
+ return fOffset + x*fCoef;
+ }
+
+ void getLowHigh(double& amin, double& amax)
+ {
+ amin = fRange.fLo;
+ amax = fRange.fHi;
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Interpolator3pt(lo,mi,hi,v1,vm,v2)
+// Map values between lo mid hi to values between v1 vm v2
+//--------------------------------------------------------------------------------------
+class Interpolator3pt
+{
+
+ private:
+
+ Interpolator fSegment1;
+ Interpolator fSegment2;
+ double fMid;
+
+ public:
+
+ Interpolator3pt(double lo, double mi, double hi, double v1, double vm, double v2) :
+ fSegment1(lo, mi, v1, vm),
+ fSegment2(mi, hi, vm, v2),
+ fMid(mi) {}
+ double operator()(double x) { return (x < fMid) ? fSegment1(x) : fSegment2(x); }
+
+ void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fSegment1.getLowHigh(amin, amid);
+ fSegment2.getLowHigh(amid, amax);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Abstract ValueConverter class. Converts values between UI and Faust representations
+//--------------------------------------------------------------------------------------
+class ValueConverter
+{
+
+ public:
+
+ virtual ~ValueConverter() {}
+ virtual double ui2faust(double x) = 0;
+ virtual double faust2ui(double x) = 0;
+};
+
+//--------------------------------------------------------------------------------------
+// A converter than can be updated
+//--------------------------------------------------------------------------------------
+
+class UpdatableValueConverter : public ValueConverter {
+
+ protected:
+
+ bool fActive;
+
+ public:
+
+ UpdatableValueConverter():fActive(true)
+ {}
+ virtual ~UpdatableValueConverter()
+ {}
+
+ virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max) = 0;
+ virtual void getMappingValues(double& amin, double& amid, double& amax) = 0;
+
+ void setActive(bool on_off) { fActive = on_off; }
+ bool getActive() { return fActive; }
+
+};
+
+
+//--------------------------------------------------------------------------------------
+// Linear conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class LinearValueConverter : public ValueConverter
+{
+
+ private:
+
+ Interpolator fUI2F;
+ Interpolator fF2UI;
+
+ public:
+
+ LinearValueConverter(double umin, double umax, double fmin, double fmax) :
+ fUI2F(umin,umax,fmin,fmax), fF2UI(fmin,fmax,umin,umax)
+ {}
+
+ LinearValueConverter() : fUI2F(0.,0.,0.,0.), fF2UI(0.,0.,0.,0.)
+ {}
+ virtual double ui2faust(double x) { return fUI2F(x); }
+ virtual double faust2ui(double x) { return fF2UI(x); }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Two segments linear conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class LinearValueConverter2 : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fUI2F;
+ Interpolator3pt fF2UI;
+
+ public:
+
+ LinearValueConverter2(double amin, double amid, double amax, double min, double init, double max) :
+ fUI2F(amin, amid, amax, min, init, max), fF2UI(min, init, max, amin, amid, amax)
+ {}
+
+ LinearValueConverter2() : fUI2F(0.,0.,0.,0.,0.,0.), fF2UI(0.,0.,0.,0.,0.,0.)
+ {}
+
+ virtual double ui2faust(double x) { return fUI2F(x); }
+ virtual double faust2ui(double x) { return fF2UI(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max)
+ {
+ fUI2F = Interpolator3pt(amin, amid, amax, min, init, max);
+ fF2UI = Interpolator3pt(min, init, max, amin, amid, amax);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fUI2F.getMappingValues(amin, amid, amax);
+ }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Logarithmic conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class LogValueConverter : public LinearValueConverter
+{
+
+ public:
+
+ LogValueConverter(double umin, double umax, double fmin, double fmax) :
+ LinearValueConverter(umin, umax, std::log(std::max<double>(DBL_MIN, fmin)), std::log(std::max<double>(DBL_MIN, fmax)))
+ {}
+
+ virtual double ui2faust(double x) { return std::exp(LinearValueConverter::ui2faust(x)); }
+ virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::log(std::max<double>(x, DBL_MIN))); }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Exponential conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class ExpValueConverter : public LinearValueConverter
+{
+
+ public:
+
+ ExpValueConverter(double umin, double umax, double fmin, double fmax) :
+ LinearValueConverter(umin, umax, std::min<double>(DBL_MAX, std::exp(fmin)), std::min<double>(DBL_MAX, std::exp(fmax)))
+ {}
+
+ virtual double ui2faust(double x) { return std::log(LinearValueConverter::ui2faust(x)); }
+ virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::min<double>(DBL_MAX, std::exp(x))); }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using an Up curve (curve 0)
+//--------------------------------------------------------------------------------------
+class AccUpConverter : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fA2F;
+ Interpolator3pt fF2A;
+
+ public:
+
+ AccUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
+ fA2F(amin,amid,amax,fmin,fmid,fmax),
+ fF2A(fmin,fmid,fmax,amin,amid,amax)
+ {}
+
+ virtual double ui2faust(double x) { return fA2F(x); }
+ virtual double faust2ui(double x) { return fF2A(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
+ {
+ //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+ fA2F = Interpolator3pt(amin, amid, amax, fmin, fmid, fmax);
+ fF2A = Interpolator3pt(fmin, fmid, fmax, amin, amid, amax);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fA2F.getMappingValues(amin, amid, amax);
+ }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using a Down curve (curve 1)
+//--------------------------------------------------------------------------------------
+class AccDownConverter : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fA2F;
+ Interpolator3pt fF2A;
+
+ public:
+
+ AccDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
+ fA2F(amin,amid,amax,fmax,fmid,fmin),
+ fF2A(fmin,fmid,fmax,amax,amid,amin)
+ {}
+
+ virtual double ui2faust(double x) { return fA2F(x); }
+ virtual double faust2ui(double x) { return fF2A(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
+ {
+ //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+ fA2F = Interpolator3pt(amin, amid, amax, fmax, fmid, fmin);
+ fF2A = Interpolator3pt(fmin, fmid, fmax, amax, amid, amin);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fA2F.getMappingValues(amin, amid, amax);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using an Up-Down curve (curve 2)
+//--------------------------------------------------------------------------------------
+class AccUpDownConverter : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fA2F;
+ Interpolator fF2A;
+
+ public:
+
+ AccUpDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
+ fA2F(amin,amid,amax,fmin,fmax,fmin),
+ fF2A(fmin,fmax,amin,amax) // Special, pseudo inverse of a non monotonic function
+ {}
+
+ virtual double ui2faust(double x) { return fA2F(x); }
+ virtual double faust2ui(double x) { return fF2A(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
+ {
+ //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+ fA2F = Interpolator3pt(amin, amid, amax, fmin, fmax, fmin);
+ fF2A = Interpolator(fmin, fmax, amin, amax);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fA2F.getMappingValues(amin, amid, amax);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using a Down-Up curve (curve 3)
+//--------------------------------------------------------------------------------------
+class AccDownUpConverter : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fA2F;
+ Interpolator fF2A;
+
+ public:
+
+ AccDownUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
+ fA2F(amin,amid,amax,fmax,fmin,fmax),
+ fF2A(fmin,fmax,amin,amax) // Special, pseudo inverse of a non monotonic function
+ {}
+
+ virtual double ui2faust(double x) { return fA2F(x); }
+ virtual double faust2ui(double x) { return fF2A(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
+ {
+ //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+ fA2F = Interpolator3pt(amin, amid, amax, fmax, fmin, fmax);
+ fF2A = Interpolator(fmin, fmax, amin, amax);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fA2F.getMappingValues(amin, amid, amax);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Base class for ZoneControl
+//--------------------------------------------------------------------------------------
+class ZoneControl
+{
+
+ protected:
+
+ FAUSTFLOAT* fZone;
+
+ public:
+
+ ZoneControl(FAUSTFLOAT* zone) : fZone(zone) {}
+ virtual ~ZoneControl() {}
+
+ virtual void update(double v) const {}
+
+ virtual void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max) {}
+ virtual void getMappingValues(double& amin, double& amid, double& amax) {}
+
+ FAUSTFLOAT* getZone() { return fZone; }
+
+ virtual void setActive(bool on_off) {}
+ virtual bool getActive() { return false; }
+
+ virtual int getCurve() { return -1; }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Useful to implement accelerometers metadata as a list of ZoneControl for each axes
+//--------------------------------------------------------------------------------------
+class ConverterZoneControl : public ZoneControl
+{
+
+ protected:
+
+ ValueConverter* fValueConverter;
+
+ public:
+
+ ConverterZoneControl(FAUSTFLOAT* zone, ValueConverter* converter) : ZoneControl(zone), fValueConverter(converter) {}
+ virtual ~ConverterZoneControl() { delete fValueConverter; } // Assuming fValueConverter is not kept elsewhere...
+
+ virtual void update(double v) const { *fZone = fValueConverter->ui2faust(v); }
+
+ ValueConverter* getConverter() { return fValueConverter; }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Association of a zone and a four value converter, each one for each possible curve.
+// Useful to implement accelerometers metadata as a list of ZoneControl for each axes
+//--------------------------------------------------------------------------------------
+class CurveZoneControl : public ZoneControl
+{
+
+ private:
+
+ std::vector<UpdatableValueConverter*> fValueConverters;
+ int fCurve;
+
+ public:
+
+ CurveZoneControl(FAUSTFLOAT* zone, int curve, double amin, double amid, double amax, double min, double init, double max) : ZoneControl(zone), fCurve(0)
+ {
+ assert(curve >= 0 && curve <= 3);
+ fValueConverters.push_back(new AccUpConverter(amin, amid, amax, min, init, max));
+ fValueConverters.push_back(new AccDownConverter(amin, amid, amax, min, init, max));
+ fValueConverters.push_back(new AccUpDownConverter(amin, amid, amax, min, init, max));
+ fValueConverters.push_back(new AccDownUpConverter(amin, amid, amax, min, init, max));
+ fCurve = curve;
+ }
+ virtual ~CurveZoneControl()
+ {
+ std::vector<UpdatableValueConverter*>::iterator it;
+ for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
+ delete(*it);
+ }
+ }
+ void update(double v) const { if (fValueConverters[fCurve]->getActive()) *fZone = fValueConverters[fCurve]->ui2faust(v); }
+
+ void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max)
+ {
+ fValueConverters[curve]->setMappingValues(amin, amid, amax, min, init, max);
+ fCurve = curve;
+ }
+
+ void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fValueConverters[fCurve]->getMappingValues(amin, amid, amax);
+ }
+
+ void setActive(bool on_off)
+ {
+ std::vector<UpdatableValueConverter*>::iterator it;
+ for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
+ (*it)->setActive(on_off);
+ }
+ }
+
+ int getCurve() { return fCurve; }
+};
+
+class ZoneReader
+{
+
+ private:
+
+ FAUSTFLOAT* fZone;
+ Interpolator fInterpolator;
+
+ public:
+
+ ZoneReader(FAUSTFLOAT* zone, double lo, double hi) : fZone(zone), fInterpolator(lo, hi, 0, 255) {}
+
+ virtual ~ZoneReader() {}
+
+ int getValue()
+ {
+ return (fZone != nullptr) ? int(fInterpolator(*fZone)) : 127;
+ }
+
+};
+
+#endif
+/************************** END ValueConverter.h **************************/
+
+class APIUI : public PathBuilder, public Meta, public UI
+{
+ public:
+
+ enum ItemType { kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry, kHBargraph, kVBargraph };
+
+ protected:
+
+ enum { kLin = 0, kLog = 1, kExp = 2 };
+
+ int fNumParameters;
+ std::vector<std::string> fPaths;
+ std::vector<std::string> fLabels;
+ std::map<std::string, int> fPathMap;
+ std::map<std::string, int> fLabelMap;
+ std::vector<ValueConverter*> fConversion;
+ std::vector<FAUSTFLOAT*> fZone;
+ std::vector<FAUSTFLOAT> fInit;
+ std::vector<FAUSTFLOAT> fMin;
+ std::vector<FAUSTFLOAT> fMax;
+ std::vector<FAUSTFLOAT> fStep;
+ std::vector<ItemType> fItemType;
+ std::vector<std::map<std::string, std::string> > fMetaData;
+ std::vector<ZoneControl*> fAcc[3];
+ std::vector<ZoneControl*> fGyr[3];
+
+ // Screen color control
+ // "...[screencolor:red]..." etc.
+ bool fHasScreenControl; // true if control screen color metadata
+ ZoneReader* fRedReader;
+ ZoneReader* fGreenReader;
+ ZoneReader* fBlueReader;
+
+ // Current values controlled by metadata
+ std::string fCurrentUnit;
+ int fCurrentScale;
+ std::string fCurrentAcc;
+ std::string fCurrentGyr;
+ std::string fCurrentColor;
+ std::string fCurrentTooltip;
+ std::map<std::string, std::string> fCurrentMetadata;
+
+ // Add a generic parameter
+ virtual void addParameter(const char* label,
+ FAUSTFLOAT* zone,
+ FAUSTFLOAT init,
+ FAUSTFLOAT min,
+ FAUSTFLOAT max,
+ FAUSTFLOAT step,
+ ItemType type)
+ {
+ std::string path = buildPath(label);
+ fPathMap[path] = fLabelMap[label] = fNumParameters++;
+ fPaths.push_back(path);
+ fLabels.push_back(label);
+ fZone.push_back(zone);
+ fInit.push_back(init);
+ fMin.push_back(min);
+ fMax.push_back(max);
+ fStep.push_back(step);
+ fItemType.push_back(type);
+
+ // handle scale metadata
+ switch (fCurrentScale) {
+ case kLin:
+ fConversion.push_back(new LinearValueConverter(0, 1, min, max));
+ break;
+ case kLog:
+ fConversion.push_back(new LogValueConverter(0, 1, min, max));
+ break;
+ case kExp: fConversion.push_back(new ExpValueConverter(0, 1, min, max));
+ break;
+ }
+ fCurrentScale = kLin;
+
+ if (fCurrentAcc.size() > 0 && fCurrentGyr.size() > 0) {
+ std::cerr << "warning : 'acc' and 'gyr' metadata used for the same " << label << " parameter !!\n";
+ }
+
+ // handle acc metadata "...[acc : <axe> <curve> <amin> <amid> <amax>]..."
+ if (fCurrentAcc.size() > 0) {
+ std::istringstream iss(fCurrentAcc);
+ int axe, curve;
+ double amin, amid, amax;
+ iss >> axe >> curve >> amin >> amid >> amax;
+
+ if ((0 <= axe) && (axe < 3) &&
+ (0 <= curve) && (curve < 4) &&
+ (amin < amax) && (amin <= amid) && (amid <= amax))
+ {
+ fAcc[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
+ } else {
+ std::cerr << "incorrect acc metadata : " << fCurrentAcc << std::endl;
+ }
+ fCurrentAcc = "";
+ }
+
+ // handle gyr metadata "...[gyr : <axe> <curve> <amin> <amid> <amax>]..."
+ if (fCurrentGyr.size() > 0) {
+ std::istringstream iss(fCurrentGyr);
+ int axe, curve;
+ double amin, amid, amax;
+ iss >> axe >> curve >> amin >> amid >> amax;
+
+ if ((0 <= axe) && (axe < 3) &&
+ (0 <= curve) && (curve < 4) &&
+ (amin < amax) && (amin <= amid) && (amid <= amax))
+ {
+ fGyr[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
+ } else {
+ std::cerr << "incorrect gyr metadata : " << fCurrentGyr << std::endl;
+ }
+ fCurrentGyr = "";
+ }
+
+ // handle screencolor metadata "...[screencolor:red|green|blue|white]..."
+ if (fCurrentColor.size() > 0) {
+ if ((fCurrentColor == "red") && (fRedReader == 0)) {
+ fRedReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else if ((fCurrentColor == "green") && (fGreenReader == 0)) {
+ fGreenReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else if ((fCurrentColor == "blue") && (fBlueReader == 0)) {
+ fBlueReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else if ((fCurrentColor == "white") && (fRedReader == 0) && (fGreenReader == 0) && (fBlueReader == 0)) {
+ fRedReader = new ZoneReader(zone, min, max);
+ fGreenReader = new ZoneReader(zone, min, max);
+ fBlueReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else {
+ std::cerr << "incorrect screencolor metadata : " << fCurrentColor << std::endl;
+ }
+ }
+ fCurrentColor = "";
+
+ fMetaData.push_back(fCurrentMetadata);
+ fCurrentMetadata.clear();
+ }
+
+ int getZoneIndex(std::vector<ZoneControl*>* table, int p, int val)
+ {
+ FAUSTFLOAT* zone = fZone[p];
+ for (size_t i = 0; i < table[val].size(); i++) {
+ if (zone == table[val][i]->getZone()) return int(i);
+ }
+ return -1;
+ }
+
+ void setConverter(std::vector<ZoneControl*>* table, int p, int val, int curve, double amin, double amid, double amax)
+ {
+ int id1 = getZoneIndex(table, p, 0);
+ int id2 = getZoneIndex(table, p, 1);
+ int id3 = getZoneIndex(table, p, 2);
+
+ // Deactivates everywhere..
+ if (id1 != -1) table[0][id1]->setActive(false);
+ if (id2 != -1) table[1][id2]->setActive(false);
+ if (id3 != -1) table[2][id3]->setActive(false);
+
+ if (val == -1) { // Means: no more mapping...
+ // So stay all deactivated...
+ } else {
+ int id4 = getZoneIndex(table, p, val);
+ if (id4 != -1) {
+ // Reactivate the one we edit...
+ table[val][id4]->setMappingValues(curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]);
+ table[val][id4]->setActive(true);
+ } else {
+ // Allocate a new CurveZoneControl which is 'active' by default
+ FAUSTFLOAT* zone = fZone[p];
+ table[val].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]));
+ }
+ }
+ }
+
+ void getConverter(std::vector<ZoneControl*>* table, int p, int& val, int& curve, double& amin, double& amid, double& amax)
+ {
+ int id1 = getZoneIndex(table, p, 0);
+ int id2 = getZoneIndex(table, p, 1);
+ int id3 = getZoneIndex(table, p, 2);
+
+ if (id1 != -1) {
+ val = 0;
+ curve = table[val][id1]->getCurve();
+ table[val][id1]->getMappingValues(amin, amid, amax);
+ } else if (id2 != -1) {
+ val = 1;
+ curve = table[val][id2]->getCurve();
+ table[val][id2]->getMappingValues(amin, amid, amax);
+ } else if (id3 != -1) {
+ val = 2;
+ curve = table[val][id3]->getCurve();
+ table[val][id3]->getMappingValues(amin, amid, amax);
+ } else {
+ val = -1; // No mapping
+ curve = 0;
+ amin = -100.;
+ amid = 0.;
+ amax = 100.;
+ }
+ }
+
+ public:
+
+ enum Type { kAcc = 0, kGyr = 1, kNoType };
+
+ APIUI() : fNumParameters(0), fHasScreenControl(false), fRedReader(0), fGreenReader(0), fBlueReader(0), fCurrentScale(kLin)
+ {}
+
+ virtual ~APIUI()
+ {
+ for (auto& it : fConversion) delete it;
+ for (int i = 0; i < 3; i++) {
+ for (auto& it : fAcc[i]) delete it;
+ for (auto& it : fGyr[i]) delete it;
+ }
+ delete fRedReader;
+ delete fGreenReader;
+ delete fBlueReader;
+ }
+
+ // -- widget's layouts
+
+ virtual void openTabBox(const char* label) { pushLabel(label); }
+ virtual void openHorizontalBox(const char* label) { pushLabel(label); }
+ virtual void openVerticalBox(const char* label) { pushLabel(label); }
+ virtual void closeBox() { popLabel(); }
+
+ // -- active widgets
+
+ virtual void addButton(const char* label, FAUSTFLOAT* zone)
+ {
+ addParameter(label, zone, 0, 0, 1, 1, kButton);
+ }
+
+ virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
+ {
+ addParameter(label, zone, 0, 0, 1, 1, kCheckButton);
+ }
+
+ virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+ {
+ addParameter(label, zone, init, min, max, step, kVSlider);
+ }
+
+ virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+ {
+ addParameter(label, zone, init, min, max, step, kHSlider);
+ }
+
+ virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+ {
+ addParameter(label, zone, init, min, max, step, kNumEntry);
+ }
+
+ // -- passive widgets
+
+ virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
+ {
+ addParameter(label, zone, min, min, max, (max-min)/1000.0, kHBargraph);
+ }
+
+ virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
+ {
+ addParameter(label, zone, min, min, max, (max-min)/1000.0, kVBargraph);
+ }
+
+ // -- soundfiles
+
+ virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) {}
+
+ // -- metadata declarations
+
+ virtual void declare(FAUSTFLOAT* zone, const char* key, const char* val)
+ {
+ // Keep metadata
+ fCurrentMetadata[key] = val;
+
+ if (strcmp(key, "scale") == 0) {
+ if (strcmp(val, "log") == 0) {
+ fCurrentScale = kLog;
+ } else if (strcmp(val, "exp") == 0) {
+ fCurrentScale = kExp;
+ } else {
+ fCurrentScale = kLin;
+ }
+ } else if (strcmp(key, "unit") == 0) {
+ fCurrentUnit = val;
+ } else if (strcmp(key, "acc") == 0) {
+ fCurrentAcc = val;
+ } else if (strcmp(key, "gyr") == 0) {
+ fCurrentGyr = val;
+ } else if (strcmp(key, "screencolor") == 0) {
+ fCurrentColor = val; // val = "red", "green", "blue" or "white"
+ } else if (strcmp(key, "tooltip") == 0) {
+ fCurrentTooltip = val;
+ }
+ }
+
+ virtual void declare(const char* key, const char* val)
+ {}
+
+ //-------------------------------------------------------------------------------
+ // Simple API part
+ //-------------------------------------------------------------------------------
+ int getParamsCount() { return fNumParameters; }
+ int getParamIndex(const char* path)
+ {
+ if (fPathMap.find(path) != fPathMap.end()) {
+ return fPathMap[path];
+ } else if (fLabelMap.find(path) != fLabelMap.end()) {
+ return fLabelMap[path];
+ } else {
+ return -1;
+ }
+ }
+ const char* getParamAddress(int p) { return fPaths[p].c_str(); }
+ const char* getParamLabel(int p) { return fLabels[p].c_str(); }
+ std::map<const char*, const char*> getMetadata(int p)
+ {
+ std::map<const char*, const char*> res;
+ std::map<std::string, std::string> metadata = fMetaData[p];
+ for (auto it : metadata) {
+ res[it.first.c_str()] = it.second.c_str();
+ }
+ return res;
+ }
+
+ const char* getMetadata(int p, const char* key)
+ {
+ return (fMetaData[p].find(key) != fMetaData[p].end()) ? fMetaData[p][key].c_str() : "";
+ }
+ FAUSTFLOAT getParamMin(int p) { return fMin[p]; }
+ FAUSTFLOAT getParamMax(int p) { return fMax[p]; }
+ FAUSTFLOAT getParamStep(int p) { return fStep[p]; }
+ FAUSTFLOAT getParamInit(int p) { return fInit[p]; }
+
+ FAUSTFLOAT* getParamZone(int p) { return fZone[p]; }
+ FAUSTFLOAT getParamValue(int p) { return *fZone[p]; }
+ void setParamValue(int p, FAUSTFLOAT v) { *fZone[p] = v; }
+
+ double getParamRatio(int p) { return fConversion[p]->faust2ui(*fZone[p]); }
+ void setParamRatio(int p, double r) { *fZone[p] = fConversion[p]->ui2faust(r); }
+
+ double value2ratio(int p, double r) { return fConversion[p]->faust2ui(r); }
+ double ratio2value(int p, double r) { return fConversion[p]->ui2faust(r); }
+
+ /**
+ * Return the control type (kAcc, kGyr, or -1) for a given parameter
+ *
+ * @param p - the UI parameter index
+ *
+ * @return the type
+ */
+ Type getParamType(int p)
+ {
+ if (p >= 0) {
+ if (getZoneIndex(fAcc, p, 0) != -1
+ || getZoneIndex(fAcc, p, 1) != -1
+ || getZoneIndex(fAcc, p, 2) != -1) {
+ return kAcc;
+ } else if (getZoneIndex(fGyr, p, 0) != -1
+ || getZoneIndex(fGyr, p, 1) != -1
+ || getZoneIndex(fGyr, p, 2) != -1) {
+ return kGyr;
+ }
+ }
+ return kNoType;
+ }
+
+ /**
+ * Return the Item type (kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry, kHBargraph, kVBargraph) for a given parameter
+ *
+ * @param p - the UI parameter index
+ *
+ * @return the Item type
+ */
+ ItemType getParamItemType(int p)
+ {
+ return fItemType[p];
+ }
+
+ /**
+ * Set a new value coming from an accelerometer, propagate it to all relevant FAUSTFLOAT* zones.
+ *
+ * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+ * @param value - the new value
+ *
+ */
+ void propagateAcc(int acc, double value)
+ {
+ for (size_t i = 0; i < fAcc[acc].size(); i++) {
+ fAcc[acc][i]->update(value);
+ }
+ }
+
+ /**
+ * Used to edit accelerometer curves and mapping. Set curve and related mapping for a given UI parameter.
+ *
+ * @param p - the UI parameter index
+ * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer (-1 means "no mapping")
+ * @param curve - between 0 and 3
+ * @param amin - mapping 'min' point
+ * @param amid - mapping 'middle' point
+ * @param amax - mapping 'max' point
+ *
+ */
+ void setAccConverter(int p, int acc, int curve, double amin, double amid, double amax)
+ {
+ setConverter(fAcc, p, acc, curve, amin, amid, amax);
+ }
+
+ /**
+ * Used to edit gyroscope curves and mapping. Set curve and related mapping for a given UI parameter.
+ *
+ * @param p - the UI parameter index
+ * @param acc - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope (-1 means "no mapping")
+ * @param curve - between 0 and 3
+ * @param amin - mapping 'min' point
+ * @param amid - mapping 'middle' point
+ * @param amax - mapping 'max' point
+ *
+ */
+ void setGyrConverter(int p, int gyr, int curve, double amin, double amid, double amax)
+ {
+ setConverter(fGyr, p, gyr, curve, amin, amid, amax);
+ }
+
+ /**
+ * Used to edit accelerometer curves and mapping. Get curve and related mapping for a given UI parameter.
+ *
+ * @param p - the UI parameter index
+ * @param acc - the acc value to be retrieved (-1 means "no mapping")
+ * @param curve - the curve value to be retrieved
+ * @param amin - the amin value to be retrieved
+ * @param amid - the amid value to be retrieved
+ * @param amax - the amax value to be retrieved
+ *
+ */
+ void getAccConverter(int p, int& acc, int& curve, double& amin, double& amid, double& amax)
+ {
+ getConverter(fAcc, p, acc, curve, amin, amid, amax);
+ }
+
+ /**
+ * Used to edit gyroscope curves and mapping. Get curve and related mapping for a given UI parameter.
+ *
+ * @param p - the UI parameter index
+ * @param gyr - the gyr value to be retrieved (-1 means "no mapping")
+ * @param curve - the curve value to be retrieved
+ * @param amin - the amin value to be retrieved
+ * @param amid - the amid value to be retrieved
+ * @param amax - the amax value to be retrieved
+ *
+ */
+ void getGyrConverter(int p, int& gyr, int& curve, double& amin, double& amid, double& amax)
+ {
+ getConverter(fGyr, p, gyr, curve, amin, amid, amax);
+ }
+
+ /**
+ * Set a new value coming from an gyroscope, propagate it to all relevant FAUSTFLOAT* zones.
+ *
+ * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
+ * @param value - the new value
+ *
+ */
+ void propagateGyr(int gyr, double value)
+ {
+ for (size_t i = 0; i < fGyr[gyr].size(); i++) {
+ fGyr[gyr][i]->update(value);
+ }
+ }
+
+ /**
+ * Get the number of FAUSTFLOAT* zones controlled with the accelerometer
+ *
+ * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+ * @return the number of zones
+ *
+ */
+ int getAccCount(int acc)
+ {
+ return (acc >= 0 && acc < 3) ? int(fAcc[acc].size()) : 0;
+ }
+
+ /**
+ * Get the number of FAUSTFLOAT* zones controlled with the gyroscope
+ *
+ * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
+ * @param the number of zones
+ *
+ */
+ int getGyrCount(int gyr)
+ {
+ return (gyr >= 0 && gyr < 3) ? int(fGyr[gyr].size()) : 0;
+ }
+
+ // getScreenColor() : -1 means no screen color control (no screencolor metadata found)
+ // otherwise return 0x00RRGGBB a ready to use color
+ int getScreenColor()
+ {
+ if (fHasScreenControl) {
+ int r = (fRedReader) ? fRedReader->getValue() : 0;
+ int g = (fGreenReader) ? fGreenReader->getValue() : 0;
+ int b = (fBlueReader) ? fBlueReader->getValue() : 0;
+ return (r<<16) | (g<<8) | b;
+ } else {
+ return -1;
+ }
+ }
+
+};
+
+#endif
+/************************** END APIUI.h **************************/
+
+// NOTE: "faust -scn name" changes the last line above to
+// #include <faust/name/name.h>
+
+//----------------------------------------------------------------------------
+// FAUST Generated Code
+//----------------------------------------------------------------------------
+
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+#include <algorithm>
+#include <cmath>
+#include <math.h>
+
+
+#ifndef FAUSTCLASS
+#define FAUSTCLASS freeverbmonodsp
+#endif
+
+#ifdef __APPLE__
+#define exp10f __exp10f
+#define exp10 __exp10
+#endif
+
+class freeverbmonodsp : public dsp {
+
+ private:
+
+ FAUSTFLOAT fVslider0;
+ int fSampleRate;
+ float fConst0;
+ float fConst1;
+ FAUSTFLOAT fVslider1;
+ float fConst2;
+ FAUSTFLOAT fVslider2;
+ float fRec9[2];
+ int IOTA;
+ float fVec0[8192];
+ int iConst3;
+ float fConst4;
+ FAUSTFLOAT fVslider3;
+ float fRec8[2];
+ float fRec11[2];
+ float fVec1[8192];
+ int iConst5;
+ float fRec10[2];
+ float fRec13[2];
+ float fVec2[8192];
+ int iConst6;
+ float fRec12[2];
+ float fRec15[2];
+ float fVec3[8192];
+ int iConst7;
+ float fRec14[2];
+ float fRec17[2];
+ float fVec4[8192];
+ int iConst8;
+ float fRec16[2];
+ float fRec19[2];
+ float fVec5[8192];
+ int iConst9;
+ float fRec18[2];
+ float fRec21[2];
+ float fVec6[8192];
+ int iConst10;
+ float fRec20[2];
+ float fRec23[2];
+ float fVec7[8192];
+ int iConst11;
+ float fRec22[2];
+ float fVec8[2048];
+ int iConst12;
+ float fRec6[2];
+ float fVec9[2048];
+ int iConst13;
+ float fRec4[2];
+ float fVec10[2048];
+ int iConst14;
+ float fRec2[2];
+ float fVec11[2048];
+ int iConst15;
+ float fRec0[2];
+ float fRec33[2];
+ float fVec12[8192];
+ float fRec32[2];
+ float fRec35[2];
+ float fVec13[8192];
+ float fRec34[2];
+ float fRec37[2];
+ float fVec14[8192];
+ float fRec36[2];
+ float fRec39[2];
+ float fVec15[8192];
+ float fRec38[2];
+ float fRec41[2];
+ float fVec16[8192];
+ float fRec40[2];
+ float fRec43[2];
+ float fVec17[8192];
+ float fRec42[2];
+ float fRec45[2];
+ float fVec18[8192];
+ float fRec44[2];
+ float fRec47[2];
+ float fVec19[8192];
+ float fRec46[2];
+ float fVec20[2048];
+ int iConst16;
+ float fRec30[2];
+ float fVec21[2048];
+ int iConst17;
+ float fRec28[2];
+ float fVec22[2048];
+ int iConst18;
+ float fRec26[2];
+ float fVec23[1024];
+ int iConst19;
+ float fRec24[2];
+
+ public:
+
+ void metadata(Meta* m) {
+ m->declare("delays.lib/name", "Faust Delay Library");
+ m->declare("delays.lib/version", "0.1");
+ m->declare("filename", "freeverbmonodsp.dsp");
+ m->declare("filters.lib/allpass_comb:author", "Julius O. Smith III");
+ m->declare("filters.lib/allpass_comb:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+ m->declare("filters.lib/allpass_comb:license", "MIT-style STK-4.3 license");
+ m->declare("filters.lib/lowpass0_highpass1", "MIT-style STK-4.3 license");
+ m->declare("filters.lib/name", "Faust Filters Library");
+ m->declare("freeverbdsp.dsp/author", "Romain Michon");
+ m->declare("freeverbdsp.dsp/description", "Freeverb implementation in Faust, from the Faust Library's dm.freeverb_demo in demos.lib");
+ m->declare("freeverbdsp.dsp/license", "LGPL");
+ m->declare("freeverbdsp.dsp/name", "freeverb");
+ m->declare("freeverbdsp.dsp/version", "0.0");
+ m->declare("maths.lib/author", "GRAME");
+ m->declare("maths.lib/copyright", "GRAME");
+ m->declare("maths.lib/license", "LGPL with exception");
+ m->declare("maths.lib/name", "Faust Math Library");
+ m->declare("maths.lib/version", "2.3");
+ m->declare("name", "freeverbmonodsp");
+ m->declare("platform.lib/name", "Generic Platform Library");
+ m->declare("platform.lib/version", "0.1");
+ m->declare("reverbs.lib/name", "Faust Reverb Library");
+ m->declare("reverbs.lib/version", "0.0");
+ }
+
+ virtual int getNumInputs() {
+ return 1;
+ }
+ virtual int getNumOutputs() {
+ return 1;
+ }
+ virtual int getInputRate(int channel) {
+ int rate;
+ switch ((channel)) {
+ case 0: {
+ rate = 1;
+ break;
+ }
+ default: {
+ rate = -1;
+ break;
+ }
+ }
+ return rate;
+ }
+ virtual int getOutputRate(int channel) {
+ int rate;
+ switch ((channel)) {
+ case 0: {
+ rate = 1;
+ break;
+ }
+ default: {
+ rate = -1;
+ break;
+ }
+ }
+ return rate;
+ }
+
+ static void classInit(int sample_rate) {
+ }
+
+ virtual void instanceConstants(int sample_rate) {
+ fSampleRate = sample_rate;
+ fConst0 = std::min<float>(192000.0f, std::max<float>(1.0f, float(fSampleRate)));
+ fConst1 = (12348.0f / fConst0);
+ fConst2 = (17640.0f / fConst0);
+ iConst3 = int((0.0253061224f * fConst0));
+ fConst4 = (0.00104308384f * fConst0);
+ iConst5 = int((0.0269387756f * fConst0));
+ iConst6 = int((0.0289569162f * fConst0));
+ iConst7 = int((0.0307482984f * fConst0));
+ iConst8 = int((0.0322448984f * fConst0));
+ iConst9 = int((0.033809524f * fConst0));
+ iConst10 = int((0.0353061222f * fConst0));
+ iConst11 = int((0.0366666652f * fConst0));
+ iConst12 = int((0.0126077095f * fConst0));
+ iConst13 = int((0.00999999978f * fConst0));
+ iConst14 = int((0.00773242628f * fConst0));
+ iConst15 = int((0.00510204071f * fConst0));
+ iConst16 = std::min<int>(1024, std::max<int>(0, (iConst12 + -1)));
+ iConst17 = std::min<int>(1024, std::max<int>(0, (iConst13 + -1)));
+ iConst18 = std::min<int>(1024, std::max<int>(0, (iConst14 + -1)));
+ iConst19 = std::min<int>(1024, std::max<int>(0, (iConst15 + -1)));
+ }
+
+ virtual void instanceResetUserInterface() {
+ fVslider0 = FAUSTFLOAT(0.10000000000000001f);
+ fVslider1 = FAUSTFLOAT(0.10000000000000001f);
+ fVslider2 = FAUSTFLOAT(0.5f);
+ fVslider3 = FAUSTFLOAT(0.5f);
+ }
+
+ virtual void instanceClear() {
+ for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) {
+ fRec9[l0] = 0.0f;
+ }
+ IOTA = 0;
+ for (int l1 = 0; (l1 < 8192); l1 = (l1 + 1)) {
+ fVec0[l1] = 0.0f;
+ }
+ for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) {
+ fRec8[l2] = 0.0f;
+ }
+ for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) {
+ fRec11[l3] = 0.0f;
+ }
+ for (int l4 = 0; (l4 < 8192); l4 = (l4 + 1)) {
+ fVec1[l4] = 0.0f;
+ }
+ for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) {
+ fRec10[l5] = 0.0f;
+ }
+ for (int l6 = 0; (l6 < 2); l6 = (l6 + 1)) {
+ fRec13[l6] = 0.0f;
+ }
+ for (int l7 = 0; (l7 < 8192); l7 = (l7 + 1)) {
+ fVec2[l7] = 0.0f;
+ }
+ for (int l8 = 0; (l8 < 2); l8 = (l8 + 1)) {
+ fRec12[l8] = 0.0f;
+ }
+ for (int l9 = 0; (l9 < 2); l9 = (l9 + 1)) {
+ fRec15[l9] = 0.0f;
+ }
+ for (int l10 = 0; (l10 < 8192); l10 = (l10 + 1)) {
+ fVec3[l10] = 0.0f;
+ }
+ for (int l11 = 0; (l11 < 2); l11 = (l11 + 1)) {
+ fRec14[l11] = 0.0f;
+ }
+ for (int l12 = 0; (l12 < 2); l12 = (l12 + 1)) {
+ fRec17[l12] = 0.0f;
+ }
+ for (int l13 = 0; (l13 < 8192); l13 = (l13 + 1)) {
+ fVec4[l13] = 0.0f;
+ }
+ for (int l14 = 0; (l14 < 2); l14 = (l14 + 1)) {
+ fRec16[l14] = 0.0f;
+ }
+ for (int l15 = 0; (l15 < 2); l15 = (l15 + 1)) {
+ fRec19[l15] = 0.0f;
+ }
+ for (int l16 = 0; (l16 < 8192); l16 = (l16 + 1)) {
+ fVec5[l16] = 0.0f;
+ }
+ for (int l17 = 0; (l17 < 2); l17 = (l17 + 1)) {
+ fRec18[l17] = 0.0f;
+ }
+ for (int l18 = 0; (l18 < 2); l18 = (l18 + 1)) {
+ fRec21[l18] = 0.0f;
+ }
+ for (int l19 = 0; (l19 < 8192); l19 = (l19 + 1)) {
+ fVec6[l19] = 0.0f;
+ }
+ for (int l20 = 0; (l20 < 2); l20 = (l20 + 1)) {
+ fRec20[l20] = 0.0f;
+ }
+ for (int l21 = 0; (l21 < 2); l21 = (l21 + 1)) {
+ fRec23[l21] = 0.0f;
+ }
+ for (int l22 = 0; (l22 < 8192); l22 = (l22 + 1)) {
+ fVec7[l22] = 0.0f;
+ }
+ for (int l23 = 0; (l23 < 2); l23 = (l23 + 1)) {
+ fRec22[l23] = 0.0f;
+ }
+ for (int l24 = 0; (l24 < 2048); l24 = (l24 + 1)) {
+ fVec8[l24] = 0.0f;
+ }
+ for (int l25 = 0; (l25 < 2); l25 = (l25 + 1)) {
+ fRec6[l25] = 0.0f;
+ }
+ for (int l26 = 0; (l26 < 2048); l26 = (l26 + 1)) {
+ fVec9[l26] = 0.0f;
+ }
+ for (int l27 = 0; (l27 < 2); l27 = (l27 + 1)) {
+ fRec4[l27] = 0.0f;
+ }
+ for (int l28 = 0; (l28 < 2048); l28 = (l28 + 1)) {
+ fVec10[l28] = 0.0f;
+ }
+ for (int l29 = 0; (l29 < 2); l29 = (l29 + 1)) {
+ fRec2[l29] = 0.0f;
+ }
+ for (int l30 = 0; (l30 < 2048); l30 = (l30 + 1)) {
+ fVec11[l30] = 0.0f;
+ }
+ for (int l31 = 0; (l31 < 2); l31 = (l31 + 1)) {
+ fRec0[l31] = 0.0f;
+ }
+ for (int l32 = 0; (l32 < 2); l32 = (l32 + 1)) {
+ fRec33[l32] = 0.0f;
+ }
+ for (int l33 = 0; (l33 < 8192); l33 = (l33 + 1)) {
+ fVec12[l33] = 0.0f;
+ }
+ for (int l34 = 0; (l34 < 2); l34 = (l34 + 1)) {
+ fRec32[l34] = 0.0f;
+ }
+ for (int l35 = 0; (l35 < 2); l35 = (l35 + 1)) {
+ fRec35[l35] = 0.0f;
+ }
+ for (int l36 = 0; (l36 < 8192); l36 = (l36 + 1)) {
+ fVec13[l36] = 0.0f;
+ }
+ for (int l37 = 0; (l37 < 2); l37 = (l37 + 1)) {
+ fRec34[l37] = 0.0f;
+ }
+ for (int l38 = 0; (l38 < 2); l38 = (l38 + 1)) {
+ fRec37[l38] = 0.0f;
+ }
+ for (int l39 = 0; (l39 < 8192); l39 = (l39 + 1)) {
+ fVec14[l39] = 0.0f;
+ }
+ for (int l40 = 0; (l40 < 2); l40 = (l40 + 1)) {
+ fRec36[l40] = 0.0f;
+ }
+ for (int l41 = 0; (l41 < 2); l41 = (l41 + 1)) {
+ fRec39[l41] = 0.0f;
+ }
+ for (int l42 = 0; (l42 < 8192); l42 = (l42 + 1)) {
+ fVec15[l42] = 0.0f;
+ }
+ for (int l43 = 0; (l43 < 2); l43 = (l43 + 1)) {
+ fRec38[l43] = 0.0f;
+ }
+ for (int l44 = 0; (l44 < 2); l44 = (l44 + 1)) {
+ fRec41[l44] = 0.0f;
+ }
+ for (int l45 = 0; (l45 < 8192); l45 = (l45 + 1)) {
+ fVec16[l45] = 0.0f;
+ }
+ for (int l46 = 0; (l46 < 2); l46 = (l46 + 1)) {
+ fRec40[l46] = 0.0f;
+ }
+ for (int l47 = 0; (l47 < 2); l47 = (l47 + 1)) {
+ fRec43[l47] = 0.0f;
+ }
+ for (int l48 = 0; (l48 < 8192); l48 = (l48 + 1)) {
+ fVec17[l48] = 0.0f;
+ }
+ for (int l49 = 0; (l49 < 2); l49 = (l49 + 1)) {
+ fRec42[l49] = 0.0f;
+ }
+ for (int l50 = 0; (l50 < 2); l50 = (l50 + 1)) {
+ fRec45[l50] = 0.0f;
+ }
+ for (int l51 = 0; (l51 < 8192); l51 = (l51 + 1)) {
+ fVec18[l51] = 0.0f;
+ }
+ for (int l52 = 0; (l52 < 2); l52 = (l52 + 1)) {
+ fRec44[l52] = 0.0f;
+ }
+ for (int l53 = 0; (l53 < 2); l53 = (l53 + 1)) {
+ fRec47[l53] = 0.0f;
+ }
+ for (int l54 = 0; (l54 < 8192); l54 = (l54 + 1)) {
+ fVec19[l54] = 0.0f;
+ }
+ for (int l55 = 0; (l55 < 2); l55 = (l55 + 1)) {
+ fRec46[l55] = 0.0f;
+ }
+ for (int l56 = 0; (l56 < 2048); l56 = (l56 + 1)) {
+ fVec20[l56] = 0.0f;
+ }
+ for (int l57 = 0; (l57 < 2); l57 = (l57 + 1)) {
+ fRec30[l57] = 0.0f;
+ }
+ for (int l58 = 0; (l58 < 2048); l58 = (l58 + 1)) {
+ fVec21[l58] = 0.0f;
+ }
+ for (int l59 = 0; (l59 < 2); l59 = (l59 + 1)) {
+ fRec28[l59] = 0.0f;
+ }
+ for (int l60 = 0; (l60 < 2048); l60 = (l60 + 1)) {
+ fVec22[l60] = 0.0f;
+ }
+ for (int l61 = 0; (l61 < 2); l61 = (l61 + 1)) {
+ fRec26[l61] = 0.0f;
+ }
+ for (int l62 = 0; (l62 < 1024); l62 = (l62 + 1)) {
+ fVec23[l62] = 0.0f;
+ }
+ for (int l63 = 0; (l63 < 2); l63 = (l63 + 1)) {
+ fRec24[l63] = 0.0f;
+ }
+ }
+
+ virtual void init(int sample_rate) {
+ classInit(sample_rate);
+ instanceInit(sample_rate);
+ }
+ virtual void instanceInit(int sample_rate) {
+ instanceConstants(sample_rate);
+ instanceResetUserInterface();
+ instanceClear();
+ }
+
+ virtual freeverbmonodsp* clone() {
+ return new freeverbmonodsp();
+ }
+
+ virtual int getSampleRate() {
+ return fSampleRate;
+ }
+
+ virtual void buildUserInterface(UI* ui_interface) {
+ ui_interface->openHorizontalBox("Freeverb");
+ ui_interface->declare(0, "0", "");
+ ui_interface->openVerticalBox("0x00");
+ ui_interface->declare(&fVslider2, "0", "");
+ ui_interface->declare(&fVslider2, "style", "knob");
+ ui_interface->declare(&fVslider2, "tooltip", "Somehow control the density of the reverb.");
+ ui_interface->addVerticalSlider("Damp", &fVslider2, 0.5f, 0.0f, 1.0f, 0.0250000004f);
+ ui_interface->declare(&fVslider1, "1", "");
+ ui_interface->declare(&fVslider1, "style", "knob");
+ ui_interface->declare(&fVslider1, "tooltip", "The room size between 0 and 1 with 1 for the largest room.");
+ ui_interface->addVerticalSlider("RoomSize", &fVslider1, 0.100000001f, 0.0f, 1.0f, 0.0250000004f);
+ ui_interface->declare(&fVslider3, "2", "");
+ ui_interface->declare(&fVslider3, "style", "knob");
+ ui_interface->declare(&fVslider3, "tooltip", "Spatial spread between 0 and 1 with 1 for maximum spread.");
+ ui_interface->addVerticalSlider("Stereo Spread", &fVslider3, 0.5f, 0.0f, 1.0f, 0.00999999978f);
+ ui_interface->closeBox();
+ ui_interface->declare(&fVslider0, "1", "");
+ ui_interface->declare(&fVslider0, "tooltip", "The amount of reverb applied to the signal between 0 and 1 with 1 for the maximum amount of reverb.");
+ ui_interface->addVerticalSlider("Wet", &fVslider0, 0.100000001f, 0.0f, 1.0f, 0.0250000004f);
+ ui_interface->closeBox();
+ }
+
+ virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
+ FAUSTFLOAT* input0 = inputs[0];
+ FAUSTFLOAT* output0 = outputs[0];
+ float fSlow0 = float(fVslider0);
+ float fSlow1 = (0.200000003f * fSlow0);
+ float fSlow2 = ((fConst1 * float(fVslider1)) + 0.699999988f);
+ float fSlow3 = (fConst2 * float(fVslider2));
+ float fSlow4 = (1.0f - fSlow3);
+ int iSlow5 = int((fConst4 * float(fVslider3)));
+ int iSlow6 = (iConst3 + iSlow5);
+ int iSlow7 = (iConst5 + iSlow5);
+ int iSlow8 = (iConst6 + iSlow5);
+ int iSlow9 = (iConst7 + iSlow5);
+ int iSlow10 = (iConst8 + iSlow5);
+ int iSlow11 = (iConst9 + iSlow5);
+ int iSlow12 = (iConst10 + iSlow5);
+ int iSlow13 = (iConst11 + iSlow5);
+ int iSlow14 = (iSlow5 + -1);
+ int iSlow15 = std::min<int>(1024, std::max<int>(0, (iConst12 + iSlow14)));
+ int iSlow16 = std::min<int>(1024, std::max<int>(0, (iConst13 + iSlow14)));
+ int iSlow17 = std::min<int>(1024, std::max<int>(0, (iConst14 + iSlow14)));
+ int iSlow18 = std::min<int>(1024, std::max<int>(0, (iConst15 + iSlow14)));
+ float fSlow19 = (2.0f * (1.0f - fSlow0));
+ for (int i = 0; (i < count); i = (i + 1)) {
+ float fTemp0 = float(input0[i]);
+ float fTemp1 = (fSlow1 * fTemp0);
+ fRec9[0] = ((fSlow3 * fRec9[1]) + (fSlow4 * fRec8[1]));
+ fVec0[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec9[0]));
+ fRec8[0] = fVec0[((IOTA - iSlow6) & 8191)];
+ fRec11[0] = ((fSlow3 * fRec11[1]) + (fSlow4 * fRec10[1]));
+ fVec1[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec11[0]));
+ fRec10[0] = fVec1[((IOTA - iSlow7) & 8191)];
+ fRec13[0] = ((fSlow3 * fRec13[1]) + (fSlow4 * fRec12[1]));
+ fVec2[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec13[0]));
+ fRec12[0] = fVec2[((IOTA - iSlow8) & 8191)];
+ fRec15[0] = ((fSlow3 * fRec15[1]) + (fSlow4 * fRec14[1]));
+ fVec3[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec15[0]));
+ fRec14[0] = fVec3[((IOTA - iSlow9) & 8191)];
+ fRec17[0] = ((fSlow3 * fRec17[1]) + (fSlow4 * fRec16[1]));
+ fVec4[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec17[0]));
+ fRec16[0] = fVec4[((IOTA - iSlow10) & 8191)];
+ fRec19[0] = ((fSlow3 * fRec19[1]) + (fSlow4 * fRec18[1]));
+ fVec5[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec19[0]));
+ fRec18[0] = fVec5[((IOTA - iSlow11) & 8191)];
+ fRec21[0] = ((fSlow3 * fRec21[1]) + (fSlow4 * fRec20[1]));
+ fVec6[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec21[0]));
+ fRec20[0] = fVec6[((IOTA - iSlow12) & 8191)];
+ fRec23[0] = ((fSlow3 * fRec23[1]) + (fSlow4 * fRec22[1]));
+ fVec7[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec23[0]));
+ fRec22[0] = fVec7[((IOTA - iSlow13) & 8191)];
+ float fTemp2 = ((((((((fRec8[0] + fRec10[0]) + fRec12[0]) + fRec14[0]) + fRec16[0]) + fRec18[0]) + fRec20[0]) + fRec22[0]) + (0.5f * fRec6[1]));
+ fVec8[(IOTA & 2047)] = fTemp2;
+ fRec6[0] = fVec8[((IOTA - iSlow15) & 2047)];
+ float fRec7 = (0.0f - (0.5f * fTemp2));
+ float fTemp3 = (fRec6[1] + (fRec7 + (0.5f * fRec4[1])));
+ fVec9[(IOTA & 2047)] = fTemp3;
+ fRec4[0] = fVec9[((IOTA - iSlow16) & 2047)];
+ float fRec5 = (0.0f - (0.5f * fTemp3));
+ float fTemp4 = (fRec4[1] + (fRec5 + (0.5f * fRec2[1])));
+ fVec10[(IOTA & 2047)] = fTemp4;
+ fRec2[0] = fVec10[((IOTA - iSlow17) & 2047)];
+ float fRec3 = (0.0f - (0.5f * fTemp4));
+ float fTemp5 = (fRec2[1] + (fRec3 + (0.5f * fRec0[1])));
+ fVec11[(IOTA & 2047)] = fTemp5;
+ fRec0[0] = fVec11[((IOTA - iSlow18) & 2047)];
+ float fRec1 = (0.0f - (0.5f * fTemp5));
+ fRec33[0] = ((fSlow3 * fRec33[1]) + (fSlow4 * fRec32[1]));
+ fVec12[(IOTA & 8191)] = ((fSlow2 * fRec33[0]) + fTemp1);
+ fRec32[0] = fVec12[((IOTA - iConst3) & 8191)];
+ fRec35[0] = ((fSlow3 * fRec35[1]) + (fSlow4 * fRec34[1]));
+ fVec13[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec35[0]));
+ fRec34[0] = fVec13[((IOTA - iConst5) & 8191)];
+ fRec37[0] = ((fSlow3 * fRec37[1]) + (fSlow4 * fRec36[1]));
+ fVec14[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec37[0]));
+ fRec36[0] = fVec14[((IOTA - iConst6) & 8191)];
+ fRec39[0] = ((fSlow3 * fRec39[1]) + (fSlow4 * fRec38[1]));
+ fVec15[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec39[0]));
+ fRec38[0] = fVec15[((IOTA - iConst7) & 8191)];
+ fRec41[0] = ((fSlow3 * fRec41[1]) + (fSlow4 * fRec40[1]));
+ fVec16[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec41[0]));
+ fRec40[0] = fVec16[((IOTA - iConst8) & 8191)];
+ fRec43[0] = ((fSlow3 * fRec43[1]) + (fSlow4 * fRec42[1]));
+ fVec17[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec43[0]));
+ fRec42[0] = fVec17[((IOTA - iConst9) & 8191)];
+ fRec45[0] = ((fSlow3 * fRec45[1]) + (fSlow4 * fRec44[1]));
+ fVec18[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec45[0]));
+ fRec44[0] = fVec18[((IOTA - iConst10) & 8191)];
+ fRec47[0] = ((fSlow3 * fRec47[1]) + (fSlow4 * fRec46[1]));
+ fVec19[(IOTA & 8191)] = (fTemp1 + (fSlow2 * fRec47[0]));
+ fRec46[0] = fVec19[((IOTA - iConst11) & 8191)];
+ float fTemp6 = ((((((((fRec32[0] + fRec34[0]) + fRec36[0]) + fRec38[0]) + fRec40[0]) + fRec42[0]) + fRec44[0]) + fRec46[0]) + (0.5f * fRec30[1]));
+ fVec20[(IOTA & 2047)] = fTemp6;
+ fRec30[0] = fVec20[((IOTA - iConst16) & 2047)];
+ float fRec31 = (0.0f - (0.5f * fTemp6));
+ float fTemp7 = (fRec30[1] + (fRec31 + (0.5f * fRec28[1])));
+ fVec21[(IOTA & 2047)] = fTemp7;
+ fRec28[0] = fVec21[((IOTA - iConst17) & 2047)];
+ float fRec29 = (0.0f - (0.5f * fTemp7));
+ float fTemp8 = (fRec28[1] + (fRec29 + (0.5f * fRec26[1])));
+ fVec22[(IOTA & 2047)] = fTemp8;
+ fRec26[0] = fVec22[((IOTA - iConst18) & 2047)];
+ float fRec27 = (0.0f - (0.5f * fTemp8));
+ float fTemp9 = (fRec26[1] + (fRec27 + (0.5f * fRec24[1])));
+ fVec23[(IOTA & 1023)] = fTemp9;
+ fRec24[0] = fVec23[((IOTA - iConst19) & 1023)];
+ float fRec25 = (0.0f - (0.5f * fTemp9));
+ output0[i] = FAUSTFLOAT((fRec0[1] + ((fRec24[1] + (fRec25 + fRec1)) + (fSlow19 * fTemp0))));
+ fRec9[1] = fRec9[0];
+ IOTA = (IOTA + 1);
+ fRec8[1] = fRec8[0];
+ fRec11[1] = fRec11[0];
+ fRec10[1] = fRec10[0];
+ fRec13[1] = fRec13[0];
+ fRec12[1] = fRec12[0];
+ fRec15[1] = fRec15[0];
+ fRec14[1] = fRec14[0];
+ fRec17[1] = fRec17[0];
+ fRec16[1] = fRec16[0];
+ fRec19[1] = fRec19[0];
+ fRec18[1] = fRec18[0];
+ fRec21[1] = fRec21[0];
+ fRec20[1] = fRec20[0];
+ fRec23[1] = fRec23[0];
+ fRec22[1] = fRec22[0];
+ fRec6[1] = fRec6[0];
+ fRec4[1] = fRec4[0];
+ fRec2[1] = fRec2[0];
+ fRec0[1] = fRec0[0];
+ fRec33[1] = fRec33[0];
+ fRec32[1] = fRec32[0];
+ fRec35[1] = fRec35[0];
+ fRec34[1] = fRec34[0];
+ fRec37[1] = fRec37[0];
+ fRec36[1] = fRec36[0];
+ fRec39[1] = fRec39[0];
+ fRec38[1] = fRec38[0];
+ fRec41[1] = fRec41[0];
+ fRec40[1] = fRec40[0];
+ fRec43[1] = fRec43[0];
+ fRec42[1] = fRec42[0];
+ fRec45[1] = fRec45[0];
+ fRec44[1] = fRec44[0];
+ fRec47[1] = fRec47[0];
+ fRec46[1] = fRec46[0];
+ fRec30[1] = fRec30[0];
+ fRec28[1] = fRec28[0];
+ fRec26[1] = fRec26[0];
+ fRec24[1] = fRec24[0];
+ }
+ }
+
+};
+
+#endif
diff --git a/src/jacktrip.pro b/src/jacktrip.pro
index f898c63..0157e90 100644
--- a/src/jacktrip.pro
+++ b/src/jacktrip.pro
@@ -110,7 +110,13 @@ win32 {
DESTDIR = .
QMAKE_CLEAN += -r ./jacktrip ./jacktrip_debug ./release ./debug
-target.path = /usr/bin
+
+# isEmpty(PREFIX) will allow path to be changed during the command line
+# call to qmake, e.g. qmake PREFIX=/usr
+isEmpty(PREFIX) {
+ PREFIX = /usr/local
+}
+target.path = $$PREFIX/bin/
INSTALLS += target
# for plugins
@@ -120,11 +126,18 @@ INCLUDEPATH += ../faust-src-lair
HEADERS += DataProtocol.h \
JMess.h \
JackTrip.h \
+ Effects.h \
+ Compressor.h \
+ CompressorPresets.h \
+ Limiter.h \
+ Reverb.h \
+ AudioTester.h \
jacktrip_globals.h \
jacktrip_types.h \
JackTripThread.h \
JackTripWorker.h \
JackTripWorkerMessages.h \
+ JitterBuffer.h \
LoopBack.h \
NetKS.h \
PacketHeader.h \
@@ -136,7 +149,10 @@ HEADERS += DataProtocol.h \
ThreadPoolTest.h \
UdpDataProtocol.h \
UdpHubListener.h \
- AudioInterface.h
+ AudioInterface.h \
+ compressordsp.h \
+ limiterdsp.h \
+ freeverbdsp.h
!nojack {
HEADERS += JackAudioInterface.h
@@ -144,11 +160,16 @@ HEADERS += JackAudioInterface.h
SOURCES += DataProtocol.cpp \
JMess.cpp \
JackTrip.cpp \
+ Compressor.cpp \
+ Limiter.cpp \
+ Reverb.cpp \
+ AudioTester.cpp \
jacktrip_globals.cpp \
jacktrip_main.cpp \
jacktrip_tests.cpp \
JackTripThread.cpp \
JackTripWorker.cpp \
+ JitterBuffer.cpp \
LoopBack.cpp \
PacketHeader.cpp \
ProcessPlugin.cpp \
@@ -162,7 +183,7 @@ SOURCES += DataProtocol.cpp \
SOURCES += JackAudioInterface.cpp
}
-# RtAduio Input
+# RtAudio Input
win32 {
INCLUDEPATH += ../externals/rtaudio-4.1.1/include
DEPENDPATH += ../externals/rtaudio-4.1.1/include
diff --git a/src/jacktrip_globals.cpp b/src/jacktrip_globals.cpp
index 5bd9a54..7e75994 100644
--- a/src/jacktrip_globals.cpp
+++ b/src/jacktrip_globals.cpp
@@ -151,6 +151,7 @@ void setRealtimeProcessPriority()
#ifdef __UBUNTU__
priority = 95; // anything higher is silently ignored by Ubuntu 18.04
#endif
+ priority = 3;
struct sched_param sp = { .sched_priority = priority };
diff --git a/src/jacktrip_globals.h b/src/jacktrip_globals.h
index 4c98f17..ab66d2b 100644
--- a/src/jacktrip_globals.h
+++ b/src/jacktrip_globals.h
@@ -44,7 +44,7 @@
/// \todo Add this namespace
//namespace JackTrip
-const char* const gVersion = "1.2.2"; ///< JackTrip version
+const char* const gVersion = "1.3.0"; ///< JackTrip version
//*******************************************************************************
/// \name Default Values
@@ -126,6 +126,7 @@ extern int gVerboseFlag; ///< Verbose mode flag declaration
//@{
const int gJackBitResolution = 32; ///< Audio Bit Resolution of the Jack Server
const QString gJackDefaultClientName = "JackTrip";
+const int gMaxRemoteNameLength = 64;
//@}
diff --git a/src/jacktrip_main.cpp b/src/jacktrip_main.cpp
index 5e172a8..bd4ed14 100644
--- a/src/jacktrip_main.cpp
+++ b/src/jacktrip_main.cpp
@@ -38,75 +38,115 @@
#include <iostream>
#include <QCoreApplication>
-#include <QDebug>
+#include <QScopedPointer>
+#include <iostream>
+#include <signal.h>
+#include "jacktrip_globals.h"
+#include "Settings.h"
+#include "UdpHubListener.h"
#include <QLoggingCategory>
-#include "JackAudioInterface.h"
-#include "UdpDataProtocol.h"
-#include "RingBuffer.h"
-#include "JackTrip.h"
-#include "Settings.h"
-//#include "TestRingBuffer.h"
-#include "LoopBack.h"
-#include "PacketHeader.h"
-//#include "JackTripThread.h"
-#ifdef __RT_AUDIO__
-#include "RtAudioInterface.h"
-#endif
-#include "jacktrip_tests.cpp"
-#include "jacktrip_globals.h"
+void qtMessageHandler(__attribute__((unused)) QtMsgType type, __attribute__((unused)) const QMessageLogContext &context, const QString &msg)
+{
+ std::cerr << msg.toStdString() << std::endl;
+}
+
+#if defined (__LINUX__) || (__MAC_OSX__)
+static int setupUnixSignalHandler(void (*handler)(int))
+{
+ //Setup our SIGINT handler.
+ struct sigaction sigInt;
+ sigInt.sa_handler = handler;
+ sigemptyset(&sigInt.sa_mask);
+ sigInt.sa_flags = 0;
+ sigInt.sa_flags |= SA_RESTART;
+ int result = 0;
+ if (sigaction(SIGINT, &sigInt, 0)) {
+ std::cout << "Unable to register SIGINT handler" << std::endl;
+ result |= 1;
+ }
+ if (sigaction(SIGTERM, &sigInt, 0)) {
+ std::cout << "Unable to register SIGTERM handler" << std::endl;
+ result |= 2;
+ }
+ return result;
+}
+#else
+bool isHubServer = false;
-void qtMessageHandler(QtMsgType /*type*/, const QMessageLogContext& /*context*/, const QString& msg)
+BOOL WINAPI windowsCtrlHandler(DWORD fdwCtrlType)
{
- std::cerr << msg.toStdString() << std::endl;
+ switch (fdwCtrlType) {
+ case CTRL_C_EVENT:
+ if (isHubServer) {
+ UdpHubListener::sigIntHandler(0);
+ } else {
+ JackTrip::sigIntHandler(0);
+ }
+ return true;
+ default:
+ return false;
+ }
}
+#endif
-int main(int argc, char** argv)
+int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
+ QScopedPointer<JackTrip> jackTrip;
+ QScopedPointer<UdpHubListener> udpHub;
+
QLoggingCategory::setFilterRules(QStringLiteral("*.debug=true"));
qInstallMessageHandler(qtMessageHandler);
- bool testing = false;
- if ( argc > 1 ) {
- if ( !strcmp(argv[1], "test") ) {
- testing = true;
- }
- }
-
- if ( testing ) {
- std::cout << "=========TESTING=========" << std::endl;
- //main_tests(argc, argv); // test functions
- JackTrip jacktrip;
- //RtAudioInterface rtaudio(&jacktrip);
- //rtaudio.setup();
- //rtaudio.listAllInterfaces();
- //rtaudio.printDeviceInfo(0);
-
- //while (true) sleep(9999);
- }
- else {
- // catch all potential exeptions
- try
- {
- // Get Settings from user
- // ----------------------
- Settings* settings = new Settings;
- settings->parseInput(argc, argv);
- settings->startJackTrip();
- }
- catch ( const std::exception & e )
- {
- std::cerr << "ERROR:" << std::endl;
- std::cerr << e.what() << std::endl;
- std::cerr << "Exiting JackTrip..." << std::endl;
- std::cerr << gPrintSeparator << std::endl;
- return -1;
+ try {
+ Settings settings;
+ settings.parseInput(argc, argv);
+
+ //Either start our hub server or our jacktrip process as appropriate.
+ if (settings.isHubServer()) {
+ udpHub.reset(settings.getConfiguredHubServer());
+ if (gVerboseFlag) std::cout << "Settings:startJackTrip before udphub->start" << std::endl;
+ QObject::connect(udpHub.data(), &UdpHubListener::signalStopped, &app,
+ &QCoreApplication::quit, Qt::QueuedConnection);
+ QObject::connect(udpHub.data(), &UdpHubListener::signalError, &app,
+ &QCoreApplication::quit, Qt::QueuedConnection);
+#if defined (__LINUX__) || (__MAC_OSX__)
+ setupUnixSignalHandler(UdpHubListener::sigIntHandler);
+#else
+ isHubServer = true;
+ SetConsoleCtrlHandler(windowsCtrlHandler, true);
+#endif
+ udpHub->start();
+ } else {
+ jackTrip.reset(settings.getConfiguredJackTrip());
+ if (gVerboseFlag) std::cout << "Settings:startJackTrip before mJackTrip->startProcess" << std::endl;
+ QObject::connect(jackTrip.data(), &JackTrip::signalProcessesStopped, &app,
+ &QCoreApplication::quit, Qt::QueuedConnection);
+ QObject::connect(jackTrip.data(), &JackTrip::signalError, &app,
+ &QCoreApplication::quit, Qt::QueuedConnection);
+#if defined (__LINUX__) || (__MAC_OSX__)
+ setupUnixSignalHandler(JackTrip::sigIntHandler);
+#else
+ std::cout << SetConsoleCtrlHandler(windowsCtrlHandler, true) << std::endl;
+#endif
+#ifdef WAIRTOHUB // WAIR
+ jackTrip->startProcess(0); // for WAIR compatibility, ID in jack client name
+#else
+ jackTrip->startProcess();
+#endif // endwhere
}
+
+ if (gVerboseFlag) std::cout << "step 6" << std::endl;
+ if (gVerboseFlag) std::cout << "jmain before app->exec()" << std::endl;
+ } catch (const std::exception &e) {
+ std::cerr << "ERROR:" << std::endl;
+ std::cerr << e.what() << std::endl;
+ std::cerr << "Exiting JackTrip..." << std::endl;
+ std::cerr << gPrintSeparator << std::endl;
+ return -1;
}
- if (gVerboseFlag) std::cout << "step 6" << std::endl;
- if (gVerboseFlag) std::cout << "jacktrip_main before app.exec()" << std::endl;
-
+
return app.exec();
}
diff --git a/src/jacktrip_types_alt.h b/src/jacktrip_types_alt.h
new file mode 100644
index 0000000..2ce854b
--- /dev/null
+++ b/src/jacktrip_types_alt.h
@@ -0,0 +1,7 @@
+typedef float sample_t;
+typedef unsigned char uint8_t;
+typedef unsigned short int uint16_t;
+typedef unsigned int uint32_t;
+typedef signed char int8_t;
+typedef short int int16_t;
+typedef int int32_t;
diff --git a/src/limiterdsp.h b/src/limiterdsp.h
new file mode 100644
index 0000000..21ab621
--- /dev/null
+++ b/src/limiterdsp.h
@@ -0,0 +1,1751 @@
+/* ------------------------------------------------------------
+name: "limiterdsp"
+Code generated with Faust 2.28.6 (https://faust.grame.fr)
+Compilation options: -lang cpp -inpl -scal -ftz 0
+------------------------------------------------------------ */
+
+#ifndef __limiterdsp_H__
+#define __limiterdsp_H__
+
+// NOTE: ANY INCLUDE-GUARD HERE MUST BE DERIVED FROM THE CLASS NAME
+//
+// faust2header.cpp - FAUST Architecture File
+// This is a simple variation of matlabplot.cpp in the Faust distribution
+// aimed at creating a simple C++ header file (.h) containing a Faust DSP.
+// See the Makefile for how to use it.
+
+/************************** BEGIN dsp.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __dsp__
+#define __dsp__
+
+#include <string>
+#include <vector>
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+struct UI;
+struct Meta;
+
+/**
+ * DSP memory manager.
+ */
+
+struct dsp_memory_manager {
+
+ virtual ~dsp_memory_manager() {}
+
+ virtual void* allocate(size_t size) = 0;
+ virtual void destroy(void* ptr) = 0;
+
+};
+
+/**
+* Signal processor definition.
+*/
+
+class dsp {
+
+ public:
+
+ dsp() {}
+ virtual ~dsp() {}
+
+ /* Return instance number of audio inputs */
+ virtual int getNumInputs() = 0;
+
+ /* Return instance number of audio outputs */
+ virtual int getNumOutputs() = 0;
+
+ /**
+ * Trigger the ui_interface parameter with instance specific calls
+ * to 'openTabBox', 'addButton', 'addVerticalSlider'... in order to build the UI.
+ *
+ * @param ui_interface - the user interface builder
+ */
+ virtual void buildUserInterface(UI* ui_interface) = 0;
+
+ /* Returns the sample rate currently used by the instance */
+ virtual int getSampleRate() = 0;
+
+ /**
+ * Global init, calls the following methods:
+ * - static class 'classInit': static tables initialization
+ * - 'instanceInit': constants and instance state initialization
+ *
+ * @param sample_rate - the sampling rate in Hertz
+ */
+ virtual void init(int sample_rate) = 0;
+
+ /**
+ * Init instance state
+ *
+ * @param sample_rate - the sampling rate in Hertz
+ */
+ virtual void instanceInit(int sample_rate) = 0;
+
+ /**
+ * Init instance constant state
+ *
+ * @param sample_rate - the sampling rate in Hertz
+ */
+ virtual void instanceConstants(int sample_rate) = 0;
+
+ /* Init default control parameters values */
+ virtual void instanceResetUserInterface() = 0;
+
+ /* Init instance state (delay lines...) */
+ virtual void instanceClear() = 0;
+
+ /**
+ * Return a clone of the instance.
+ *
+ * @return a copy of the instance on success, otherwise a null pointer.
+ */
+ virtual dsp* clone() = 0;
+
+ /**
+ * Trigger the Meta* parameter with instance specific calls to 'declare' (key, value) metadata.
+ *
+ * @param m - the Meta* meta user
+ */
+ virtual void metadata(Meta* m) = 0;
+
+ /**
+ * DSP instance computation, to be called with successive in/out audio buffers.
+ *
+ * @param count - the number of frames to compute
+ * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
+ * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
+ *
+ */
+ virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) = 0;
+
+ /**
+ * DSP instance computation: alternative method to be used by subclasses.
+ *
+ * @param date_usec - the timestamp in microsec given by audio driver.
+ * @param count - the number of frames to compute
+ * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
+ * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
+ *
+ */
+ virtual void compute(double /*date_usec*/, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { compute(count, inputs, outputs); }
+
+};
+
+/**
+ * Generic DSP decorator.
+ */
+
+class decorator_dsp : public dsp {
+
+ protected:
+
+ dsp* fDSP;
+
+ public:
+
+ decorator_dsp(dsp* dsp = nullptr):fDSP(dsp) {}
+ virtual ~decorator_dsp() { delete fDSP; }
+
+ virtual int getNumInputs() { return fDSP->getNumInputs(); }
+ virtual int getNumOutputs() { return fDSP->getNumOutputs(); }
+ virtual void buildUserInterface(UI* ui_interface) { fDSP->buildUserInterface(ui_interface); }
+ virtual int getSampleRate() { return fDSP->getSampleRate(); }
+ virtual void init(int sample_rate) { fDSP->init(sample_rate); }
+ virtual void instanceInit(int sample_rate) { fDSP->instanceInit(sample_rate); }
+ virtual void instanceConstants(int sample_rate) { fDSP->instanceConstants(sample_rate); }
+ virtual void instanceResetUserInterface() { fDSP->instanceResetUserInterface(); }
+ virtual void instanceClear() { fDSP->instanceClear(); }
+ virtual decorator_dsp* clone() { return new decorator_dsp(fDSP->clone()); }
+ virtual void metadata(Meta* m) { fDSP->metadata(m); }
+ // Beware: subclasses usually have to overload the two 'compute' methods
+ virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(count, inputs, outputs); }
+ virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(date_usec, count, inputs, outputs); }
+
+};
+
+/**
+ * DSP factory class.
+ */
+
+class dsp_factory {
+
+ protected:
+
+ // So that to force sub-classes to use deleteDSPFactory(dsp_factory* factory);
+ virtual ~dsp_factory() {}
+
+ public:
+
+ virtual std::string getName() = 0;
+ virtual std::string getSHAKey() = 0;
+ virtual std::string getDSPCode() = 0;
+ virtual std::string getCompileOptions() = 0;
+ virtual std::vector<std::string> getLibraryList() = 0;
+ virtual std::vector<std::string> getIncludePathnames() = 0;
+
+ virtual dsp* createDSPInstance() = 0;
+
+ virtual void setMemoryManager(dsp_memory_manager* manager) = 0;
+ virtual dsp_memory_manager* getMemoryManager() = 0;
+
+};
+
+/**
+ * On Intel set FZ (Flush to Zero) and DAZ (Denormals Are Zero)
+ * flags to avoid costly denormals.
+ */
+
+#ifdef __SSE__
+ #include <xmmintrin.h>
+ #ifdef __SSE2__
+ #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
+ #else
+ #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
+ #endif
+#else
+ #define AVOIDDENORMALS
+#endif
+
+#endif
+/************************** END dsp.h **************************/
+
+/************************** BEGIN APIUI.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef API_UI_H
+#define API_UI_H
+
+#include <sstream>
+#include <string>
+#include <vector>
+#include <iostream>
+#include <map>
+
+/************************** BEGIN meta.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __meta__
+#define __meta__
+
+struct Meta
+{
+ virtual ~Meta() {};
+ virtual void declare(const char* key, const char* value) = 0;
+
+};
+
+#endif
+/************************** END meta.h **************************/
+/************************** BEGIN UI.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2020 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __UI_H__
+#define __UI_H__
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+/*******************************************************************************
+ * UI : Faust DSP User Interface
+ * User Interface as expected by the buildUserInterface() method of a DSP.
+ * This abstract class contains only the method that the Faust compiler can
+ * generate to describe a DSP user interface.
+ ******************************************************************************/
+
+struct Soundfile;
+
+template <typename REAL>
+struct UIReal
+{
+ UIReal() {}
+ virtual ~UIReal() {}
+
+ // -- widget's layouts
+
+ virtual void openTabBox(const char* label) = 0;
+ virtual void openHorizontalBox(const char* label) = 0;
+ virtual void openVerticalBox(const char* label) = 0;
+ virtual void closeBox() = 0;
+
+ // -- active widgets
+
+ virtual void addButton(const char* label, REAL* zone) = 0;
+ virtual void addCheckButton(const char* label, REAL* zone) = 0;
+ virtual void addVerticalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
+ virtual void addHorizontalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
+ virtual void addNumEntry(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
+
+ // -- passive widgets
+
+ virtual void addHorizontalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
+ virtual void addVerticalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
+
+ // -- soundfiles
+
+ virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) = 0;
+
+ // -- metadata declarations
+
+ virtual void declare(REAL* zone, const char* key, const char* val) {}
+};
+
+struct UI : public UIReal<FAUSTFLOAT>
+{
+ UI() {}
+ virtual ~UI() {}
+};
+
+#endif
+/************************** END UI.h **************************/
+/************************** BEGIN PathBuilder.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef FAUST_PATHBUILDER_H
+#define FAUST_PATHBUILDER_H
+
+#include <vector>
+#include <string>
+#include <algorithm>
+
+/*******************************************************************************
+ * PathBuilder : Faust User Interface
+ * Helper class to build complete hierarchical path for UI items.
+ ******************************************************************************/
+
+class PathBuilder
+{
+
+ protected:
+
+ std::vector<std::string> fControlsLevel;
+
+ public:
+
+ PathBuilder() {}
+ virtual ~PathBuilder() {}
+
+ std::string buildPath(const std::string& label)
+ {
+ std::string res = "/";
+ for (size_t i = 0; i < fControlsLevel.size(); i++) {
+ res += fControlsLevel[i];
+ res += "/";
+ }
+ res += label;
+ std::replace(res.begin(), res.end(), ' ', '_');
+ return res;
+ }
+
+ std::string buildLabel(std::string label)
+ {
+ std::replace(label.begin(), label.end(), ' ', '_');
+ return label;
+ }
+
+ void pushLabel(const std::string& label) { fControlsLevel.push_back(label); }
+ void popLabel() { fControlsLevel.pop_back(); }
+
+};
+
+#endif // FAUST_PATHBUILDER_H
+/************************** END PathBuilder.h **************************/
+/************************** BEGIN ValueConverter.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __ValueConverter__
+#define __ValueConverter__
+
+/***************************************************************************************
+ ValueConverter.h
+ (GRAME, Copyright 2015-2019)
+
+Set of conversion objects used to map user interface values (for example a gui slider
+delivering values between 0 and 1) to faust values (for example a vslider between
+20 and 20000) using a log scale.
+
+-- Utilities
+
+Range(lo,hi) : clip a value x between lo and hi
+Interpolator(lo,hi,v1,v2) : Maps a value x between lo and hi to a value y between v1 and v2
+Interpolator3pt(lo,mi,hi,v1,vm,v2) : Map values between lo mid hi to values between v1 vm v2
+
+-- Value Converters
+
+ValueConverter::ui2faust(x)
+ValueConverter::faust2ui(x)
+
+-- ValueConverters used for sliders depending of the scale
+
+LinearValueConverter(umin, umax, fmin, fmax)
+LinearValueConverter2(lo, mi, hi, v1, vm, v2) using 2 segments
+LogValueConverter(umin, umax, fmin, fmax)
+ExpValueConverter(umin, umax, fmin, fmax)
+
+-- ValueConverters used for accelerometers based on 3 points
+
+AccUpConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 0
+AccDownConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 1
+AccUpDownConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 2
+AccDownUpConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 3
+
+-- lists of ZoneControl are used to implement accelerometers metadata for each axes
+
+ZoneControl(zone, valueConverter) : a zone with an accelerometer data converter
+
+-- ZoneReader are used to implement screencolor metadata
+
+ZoneReader(zone, valueConverter) : a zone with a data converter
+
+****************************************************************************************/
+
+#include <float.h>
+#include <algorithm> // std::max
+#include <cmath>
+#include <vector>
+#include <assert.h>
+
+//--------------------------------------------------------------------------------------
+// Interpolator(lo,hi,v1,v2)
+// Maps a value x between lo and hi to a value y between v1 and v2
+// y = v1 + (x-lo)/(hi-lo)*(v2-v1)
+// y = v1 + (x-lo) * coef with coef = (v2-v1)/(hi-lo)
+// y = v1 + x*coef - lo*coef
+// y = v1 - lo*coef + x*coef
+// y = offset + x*coef with offset = v1 - lo*coef
+//--------------------------------------------------------------------------------------
+class Interpolator
+{
+ private:
+
+ //--------------------------------------------------------------------------------------
+ // Range(lo,hi) clip a value between lo and hi
+ //--------------------------------------------------------------------------------------
+ struct Range
+ {
+ double fLo;
+ double fHi;
+
+ Range(double x, double y) : fLo(std::min<double>(x,y)), fHi(std::max<double>(x,y)) {}
+ double operator()(double x) { return (x<fLo) ? fLo : (x>fHi) ? fHi : x; }
+ };
+
+
+ Range fRange;
+ double fCoef;
+ double fOffset;
+
+ public:
+
+ Interpolator(double lo, double hi, double v1, double v2) : fRange(lo,hi)
+ {
+ if (hi != lo) {
+ // regular case
+ fCoef = (v2-v1)/(hi-lo);
+ fOffset = v1 - lo*fCoef;
+ } else {
+ // degenerate case, avoids division by zero
+ fCoef = 0;
+ fOffset = (v1+v2)/2;
+ }
+ }
+ double operator()(double v)
+ {
+ double x = fRange(v);
+ return fOffset + x*fCoef;
+ }
+
+ void getLowHigh(double& amin, double& amax)
+ {
+ amin = fRange.fLo;
+ amax = fRange.fHi;
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Interpolator3pt(lo,mi,hi,v1,vm,v2)
+// Map values between lo mid hi to values between v1 vm v2
+//--------------------------------------------------------------------------------------
+class Interpolator3pt
+{
+
+ private:
+
+ Interpolator fSegment1;
+ Interpolator fSegment2;
+ double fMid;
+
+ public:
+
+ Interpolator3pt(double lo, double mi, double hi, double v1, double vm, double v2) :
+ fSegment1(lo, mi, v1, vm),
+ fSegment2(mi, hi, vm, v2),
+ fMid(mi) {}
+ double operator()(double x) { return (x < fMid) ? fSegment1(x) : fSegment2(x); }
+
+ void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fSegment1.getLowHigh(amin, amid);
+ fSegment2.getLowHigh(amid, amax);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Abstract ValueConverter class. Converts values between UI and Faust representations
+//--------------------------------------------------------------------------------------
+class ValueConverter
+{
+
+ public:
+
+ virtual ~ValueConverter() {}
+ virtual double ui2faust(double x) = 0;
+ virtual double faust2ui(double x) = 0;
+};
+
+//--------------------------------------------------------------------------------------
+// A converter than can be updated
+//--------------------------------------------------------------------------------------
+
+class UpdatableValueConverter : public ValueConverter {
+
+ protected:
+
+ bool fActive;
+
+ public:
+
+ UpdatableValueConverter():fActive(true)
+ {}
+ virtual ~UpdatableValueConverter()
+ {}
+
+ virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max) = 0;
+ virtual void getMappingValues(double& amin, double& amid, double& amax) = 0;
+
+ void setActive(bool on_off) { fActive = on_off; }
+ bool getActive() { return fActive; }
+
+};
+
+
+//--------------------------------------------------------------------------------------
+// Linear conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class LinearValueConverter : public ValueConverter
+{
+
+ private:
+
+ Interpolator fUI2F;
+ Interpolator fF2UI;
+
+ public:
+
+ LinearValueConverter(double umin, double umax, double fmin, double fmax) :
+ fUI2F(umin,umax,fmin,fmax), fF2UI(fmin,fmax,umin,umax)
+ {}
+
+ LinearValueConverter() : fUI2F(0.,0.,0.,0.), fF2UI(0.,0.,0.,0.)
+ {}
+ virtual double ui2faust(double x) { return fUI2F(x); }
+ virtual double faust2ui(double x) { return fF2UI(x); }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Two segments linear conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class LinearValueConverter2 : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fUI2F;
+ Interpolator3pt fF2UI;
+
+ public:
+
+ LinearValueConverter2(double amin, double amid, double amax, double min, double init, double max) :
+ fUI2F(amin, amid, amax, min, init, max), fF2UI(min, init, max, amin, amid, amax)
+ {}
+
+ LinearValueConverter2() : fUI2F(0.,0.,0.,0.,0.,0.), fF2UI(0.,0.,0.,0.,0.,0.)
+ {}
+
+ virtual double ui2faust(double x) { return fUI2F(x); }
+ virtual double faust2ui(double x) { return fF2UI(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max)
+ {
+ fUI2F = Interpolator3pt(amin, amid, amax, min, init, max);
+ fF2UI = Interpolator3pt(min, init, max, amin, amid, amax);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fUI2F.getMappingValues(amin, amid, amax);
+ }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Logarithmic conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class LogValueConverter : public LinearValueConverter
+{
+
+ public:
+
+ LogValueConverter(double umin, double umax, double fmin, double fmax) :
+ LinearValueConverter(umin, umax, std::log(std::max<double>(DBL_MIN, fmin)), std::log(std::max<double>(DBL_MIN, fmax)))
+ {}
+
+ virtual double ui2faust(double x) { return std::exp(LinearValueConverter::ui2faust(x)); }
+ virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::log(std::max<double>(x, DBL_MIN))); }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Exponential conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class ExpValueConverter : public LinearValueConverter
+{
+
+ public:
+
+ ExpValueConverter(double umin, double umax, double fmin, double fmax) :
+ LinearValueConverter(umin, umax, std::min<double>(DBL_MAX, std::exp(fmin)), std::min<double>(DBL_MAX, std::exp(fmax)))
+ {}
+
+ virtual double ui2faust(double x) { return std::log(LinearValueConverter::ui2faust(x)); }
+ virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::min<double>(DBL_MAX, std::exp(x))); }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using an Up curve (curve 0)
+//--------------------------------------------------------------------------------------
+class AccUpConverter : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fA2F;
+ Interpolator3pt fF2A;
+
+ public:
+
+ AccUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
+ fA2F(amin,amid,amax,fmin,fmid,fmax),
+ fF2A(fmin,fmid,fmax,amin,amid,amax)
+ {}
+
+ virtual double ui2faust(double x) { return fA2F(x); }
+ virtual double faust2ui(double x) { return fF2A(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
+ {
+ //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+ fA2F = Interpolator3pt(amin, amid, amax, fmin, fmid, fmax);
+ fF2A = Interpolator3pt(fmin, fmid, fmax, amin, amid, amax);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fA2F.getMappingValues(amin, amid, amax);
+ }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using a Down curve (curve 1)
+//--------------------------------------------------------------------------------------
+class AccDownConverter : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fA2F;
+ Interpolator3pt fF2A;
+
+ public:
+
+ AccDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
+ fA2F(amin,amid,amax,fmax,fmid,fmin),
+ fF2A(fmin,fmid,fmax,amax,amid,amin)
+ {}
+
+ virtual double ui2faust(double x) { return fA2F(x); }
+ virtual double faust2ui(double x) { return fF2A(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
+ {
+ //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+ fA2F = Interpolator3pt(amin, amid, amax, fmax, fmid, fmin);
+ fF2A = Interpolator3pt(fmin, fmid, fmax, amax, amid, amin);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fA2F.getMappingValues(amin, amid, amax);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using an Up-Down curve (curve 2)
+//--------------------------------------------------------------------------------------
+class AccUpDownConverter : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fA2F;
+ Interpolator fF2A;
+
+ public:
+
+ AccUpDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
+ fA2F(amin,amid,amax,fmin,fmax,fmin),
+ fF2A(fmin,fmax,amin,amax) // Special, pseudo inverse of a non monotonic function
+ {}
+
+ virtual double ui2faust(double x) { return fA2F(x); }
+ virtual double faust2ui(double x) { return fF2A(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
+ {
+ //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+ fA2F = Interpolator3pt(amin, amid, amax, fmin, fmax, fmin);
+ fF2A = Interpolator(fmin, fmax, amin, amax);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fA2F.getMappingValues(amin, amid, amax);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using a Down-Up curve (curve 3)
+//--------------------------------------------------------------------------------------
+class AccDownUpConverter : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fA2F;
+ Interpolator fF2A;
+
+ public:
+
+ AccDownUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
+ fA2F(amin,amid,amax,fmax,fmin,fmax),
+ fF2A(fmin,fmax,amin,amax) // Special, pseudo inverse of a non monotonic function
+ {}
+
+ virtual double ui2faust(double x) { return fA2F(x); }
+ virtual double faust2ui(double x) { return fF2A(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
+ {
+ //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+ fA2F = Interpolator3pt(amin, amid, amax, fmax, fmin, fmax);
+ fF2A = Interpolator(fmin, fmax, amin, amax);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fA2F.getMappingValues(amin, amid, amax);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Base class for ZoneControl
+//--------------------------------------------------------------------------------------
+class ZoneControl
+{
+
+ protected:
+
+ FAUSTFLOAT* fZone;
+
+ public:
+
+ ZoneControl(FAUSTFLOAT* zone) : fZone(zone) {}
+ virtual ~ZoneControl() {}
+
+ virtual void update(double v) const {}
+
+ virtual void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max) {}
+ virtual void getMappingValues(double& amin, double& amid, double& amax) {}
+
+ FAUSTFLOAT* getZone() { return fZone; }
+
+ virtual void setActive(bool on_off) {}
+ virtual bool getActive() { return false; }
+
+ virtual int getCurve() { return -1; }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Useful to implement accelerometers metadata as a list of ZoneControl for each axes
+//--------------------------------------------------------------------------------------
+class ConverterZoneControl : public ZoneControl
+{
+
+ protected:
+
+ ValueConverter* fValueConverter;
+
+ public:
+
+ ConverterZoneControl(FAUSTFLOAT* zone, ValueConverter* converter) : ZoneControl(zone), fValueConverter(converter) {}
+ virtual ~ConverterZoneControl() { delete fValueConverter; } // Assuming fValueConverter is not kept elsewhere...
+
+ virtual void update(double v) const { *fZone = fValueConverter->ui2faust(v); }
+
+ ValueConverter* getConverter() { return fValueConverter; }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Association of a zone and a four value converter, each one for each possible curve.
+// Useful to implement accelerometers metadata as a list of ZoneControl for each axes
+//--------------------------------------------------------------------------------------
+class CurveZoneControl : public ZoneControl
+{
+
+ private:
+
+ std::vector<UpdatableValueConverter*> fValueConverters;
+ int fCurve;
+
+ public:
+
+ CurveZoneControl(FAUSTFLOAT* zone, int curve, double amin, double amid, double amax, double min, double init, double max) : ZoneControl(zone), fCurve(0)
+ {
+ assert(curve >= 0 && curve <= 3);
+ fValueConverters.push_back(new AccUpConverter(amin, amid, amax, min, init, max));
+ fValueConverters.push_back(new AccDownConverter(amin, amid, amax, min, init, max));
+ fValueConverters.push_back(new AccUpDownConverter(amin, amid, amax, min, init, max));
+ fValueConverters.push_back(new AccDownUpConverter(amin, amid, amax, min, init, max));
+ fCurve = curve;
+ }
+ virtual ~CurveZoneControl()
+ {
+ std::vector<UpdatableValueConverter*>::iterator it;
+ for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
+ delete(*it);
+ }
+ }
+ void update(double v) const { if (fValueConverters[fCurve]->getActive()) *fZone = fValueConverters[fCurve]->ui2faust(v); }
+
+ void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max)
+ {
+ fValueConverters[curve]->setMappingValues(amin, amid, amax, min, init, max);
+ fCurve = curve;
+ }
+
+ void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fValueConverters[fCurve]->getMappingValues(amin, amid, amax);
+ }
+
+ void setActive(bool on_off)
+ {
+ std::vector<UpdatableValueConverter*>::iterator it;
+ for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
+ (*it)->setActive(on_off);
+ }
+ }
+
+ int getCurve() { return fCurve; }
+};
+
+class ZoneReader
+{
+
+ private:
+
+ FAUSTFLOAT* fZone;
+ Interpolator fInterpolator;
+
+ public:
+
+ ZoneReader(FAUSTFLOAT* zone, double lo, double hi) : fZone(zone), fInterpolator(lo, hi, 0, 255) {}
+
+ virtual ~ZoneReader() {}
+
+ int getValue()
+ {
+ return (fZone != nullptr) ? int(fInterpolator(*fZone)) : 127;
+ }
+
+};
+
+#endif
+/************************** END ValueConverter.h **************************/
+
+class APIUI : public PathBuilder, public Meta, public UI
+{
+ public:
+
+ enum ItemType { kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry, kHBargraph, kVBargraph };
+
+ protected:
+
+ enum { kLin = 0, kLog = 1, kExp = 2 };
+
+ int fNumParameters;
+ std::vector<std::string> fPaths;
+ std::vector<std::string> fLabels;
+ std::map<std::string, int> fPathMap;
+ std::map<std::string, int> fLabelMap;
+ std::vector<ValueConverter*> fConversion;
+ std::vector<FAUSTFLOAT*> fZone;
+ std::vector<FAUSTFLOAT> fInit;
+ std::vector<FAUSTFLOAT> fMin;
+ std::vector<FAUSTFLOAT> fMax;
+ std::vector<FAUSTFLOAT> fStep;
+ std::vector<ItemType> fItemType;
+ std::vector<std::map<std::string, std::string> > fMetaData;
+ std::vector<ZoneControl*> fAcc[3];
+ std::vector<ZoneControl*> fGyr[3];
+
+ // Screen color control
+ // "...[screencolor:red]..." etc.
+ bool fHasScreenControl; // true if control screen color metadata
+ ZoneReader* fRedReader;
+ ZoneReader* fGreenReader;
+ ZoneReader* fBlueReader;
+
+ // Current values controlled by metadata
+ std::string fCurrentUnit;
+ int fCurrentScale;
+ std::string fCurrentAcc;
+ std::string fCurrentGyr;
+ std::string fCurrentColor;
+ std::string fCurrentTooltip;
+ std::map<std::string, std::string> fCurrentMetadata;
+
+ // Add a generic parameter
+ virtual void addParameter(const char* label,
+ FAUSTFLOAT* zone,
+ FAUSTFLOAT init,
+ FAUSTFLOAT min,
+ FAUSTFLOAT max,
+ FAUSTFLOAT step,
+ ItemType type)
+ {
+ std::string path = buildPath(label);
+ fPathMap[path] = fLabelMap[label] = fNumParameters++;
+ fPaths.push_back(path);
+ fLabels.push_back(label);
+ fZone.push_back(zone);
+ fInit.push_back(init);
+ fMin.push_back(min);
+ fMax.push_back(max);
+ fStep.push_back(step);
+ fItemType.push_back(type);
+
+ // handle scale metadata
+ switch (fCurrentScale) {
+ case kLin:
+ fConversion.push_back(new LinearValueConverter(0, 1, min, max));
+ break;
+ case kLog:
+ fConversion.push_back(new LogValueConverter(0, 1, min, max));
+ break;
+ case kExp: fConversion.push_back(new ExpValueConverter(0, 1, min, max));
+ break;
+ }
+ fCurrentScale = kLin;
+
+ if (fCurrentAcc.size() > 0 && fCurrentGyr.size() > 0) {
+ std::cerr << "warning : 'acc' and 'gyr' metadata used for the same " << label << " parameter !!\n";
+ }
+
+ // handle acc metadata "...[acc : <axe> <curve> <amin> <amid> <amax>]..."
+ if (fCurrentAcc.size() > 0) {
+ std::istringstream iss(fCurrentAcc);
+ int axe, curve;
+ double amin, amid, amax;
+ iss >> axe >> curve >> amin >> amid >> amax;
+
+ if ((0 <= axe) && (axe < 3) &&
+ (0 <= curve) && (curve < 4) &&
+ (amin < amax) && (amin <= amid) && (amid <= amax))
+ {
+ fAcc[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
+ } else {
+ std::cerr << "incorrect acc metadata : " << fCurrentAcc << std::endl;
+ }
+ fCurrentAcc = "";
+ }
+
+ // handle gyr metadata "...[gyr : <axe> <curve> <amin> <amid> <amax>]..."
+ if (fCurrentGyr.size() > 0) {
+ std::istringstream iss(fCurrentGyr);
+ int axe, curve;
+ double amin, amid, amax;
+ iss >> axe >> curve >> amin >> amid >> amax;
+
+ if ((0 <= axe) && (axe < 3) &&
+ (0 <= curve) && (curve < 4) &&
+ (amin < amax) && (amin <= amid) && (amid <= amax))
+ {
+ fGyr[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
+ } else {
+ std::cerr << "incorrect gyr metadata : " << fCurrentGyr << std::endl;
+ }
+ fCurrentGyr = "";
+ }
+
+ // handle screencolor metadata "...[screencolor:red|green|blue|white]..."
+ if (fCurrentColor.size() > 0) {
+ if ((fCurrentColor == "red") && (fRedReader == 0)) {
+ fRedReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else if ((fCurrentColor == "green") && (fGreenReader == 0)) {
+ fGreenReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else if ((fCurrentColor == "blue") && (fBlueReader == 0)) {
+ fBlueReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else if ((fCurrentColor == "white") && (fRedReader == 0) && (fGreenReader == 0) && (fBlueReader == 0)) {
+ fRedReader = new ZoneReader(zone, min, max);
+ fGreenReader = new ZoneReader(zone, min, max);
+ fBlueReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else {
+ std::cerr << "incorrect screencolor metadata : " << fCurrentColor << std::endl;
+ }
+ }
+ fCurrentColor = "";
+
+ fMetaData.push_back(fCurrentMetadata);
+ fCurrentMetadata.clear();
+ }
+
+ int getZoneIndex(std::vector<ZoneControl*>* table, int p, int val)
+ {
+ FAUSTFLOAT* zone = fZone[p];
+ for (size_t i = 0; i < table[val].size(); i++) {
+ if (zone == table[val][i]->getZone()) return int(i);
+ }
+ return -1;
+ }
+
+ void setConverter(std::vector<ZoneControl*>* table, int p, int val, int curve, double amin, double amid, double amax)
+ {
+ int id1 = getZoneIndex(table, p, 0);
+ int id2 = getZoneIndex(table, p, 1);
+ int id3 = getZoneIndex(table, p, 2);
+
+ // Deactivates everywhere..
+ if (id1 != -1) table[0][id1]->setActive(false);
+ if (id2 != -1) table[1][id2]->setActive(false);
+ if (id3 != -1) table[2][id3]->setActive(false);
+
+ if (val == -1) { // Means: no more mapping...
+ // So stay all deactivated...
+ } else {
+ int id4 = getZoneIndex(table, p, val);
+ if (id4 != -1) {
+ // Reactivate the one we edit...
+ table[val][id4]->setMappingValues(curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]);
+ table[val][id4]->setActive(true);
+ } else {
+ // Allocate a new CurveZoneControl which is 'active' by default
+ FAUSTFLOAT* zone = fZone[p];
+ table[val].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]));
+ }
+ }
+ }
+
+ void getConverter(std::vector<ZoneControl*>* table, int p, int& val, int& curve, double& amin, double& amid, double& amax)
+ {
+ int id1 = getZoneIndex(table, p, 0);
+ int id2 = getZoneIndex(table, p, 1);
+ int id3 = getZoneIndex(table, p, 2);
+
+ if (id1 != -1) {
+ val = 0;
+ curve = table[val][id1]->getCurve();
+ table[val][id1]->getMappingValues(amin, amid, amax);
+ } else if (id2 != -1) {
+ val = 1;
+ curve = table[val][id2]->getCurve();
+ table[val][id2]->getMappingValues(amin, amid, amax);
+ } else if (id3 != -1) {
+ val = 2;
+ curve = table[val][id3]->getCurve();
+ table[val][id3]->getMappingValues(amin, amid, amax);
+ } else {
+ val = -1; // No mapping
+ curve = 0;
+ amin = -100.;
+ amid = 0.;
+ amax = 100.;
+ }
+ }
+
+ public:
+
+ enum Type { kAcc = 0, kGyr = 1, kNoType };
+
+ APIUI() : fNumParameters(0), fHasScreenControl(false), fRedReader(0), fGreenReader(0), fBlueReader(0), fCurrentScale(kLin)
+ {}
+
+ virtual ~APIUI()
+ {
+ for (auto& it : fConversion) delete it;
+ for (int i = 0; i < 3; i++) {
+ for (auto& it : fAcc[i]) delete it;
+ for (auto& it : fGyr[i]) delete it;
+ }
+ delete fRedReader;
+ delete fGreenReader;
+ delete fBlueReader;
+ }
+
+ // -- widget's layouts
+
+ virtual void openTabBox(const char* label) { pushLabel(label); }
+ virtual void openHorizontalBox(const char* label) { pushLabel(label); }
+ virtual void openVerticalBox(const char* label) { pushLabel(label); }
+ virtual void closeBox() { popLabel(); }
+
+ // -- active widgets
+
+ virtual void addButton(const char* label, FAUSTFLOAT* zone)
+ {
+ addParameter(label, zone, 0, 0, 1, 1, kButton);
+ }
+
+ virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
+ {
+ addParameter(label, zone, 0, 0, 1, 1, kCheckButton);
+ }
+
+ virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+ {
+ addParameter(label, zone, init, min, max, step, kVSlider);
+ }
+
+ virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+ {
+ addParameter(label, zone, init, min, max, step, kHSlider);
+ }
+
+ virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+ {
+ addParameter(label, zone, init, min, max, step, kNumEntry);
+ }
+
+ // -- passive widgets
+
+ virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
+ {
+ addParameter(label, zone, min, min, max, (max-min)/1000.0, kHBargraph);
+ }
+
+ virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
+ {
+ addParameter(label, zone, min, min, max, (max-min)/1000.0, kVBargraph);
+ }
+
+ // -- soundfiles
+
+ virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) {}
+
+ // -- metadata declarations
+
+ virtual void declare(FAUSTFLOAT* zone, const char* key, const char* val)
+ {
+ // Keep metadata
+ fCurrentMetadata[key] = val;
+
+ if (strcmp(key, "scale") == 0) {
+ if (strcmp(val, "log") == 0) {
+ fCurrentScale = kLog;
+ } else if (strcmp(val, "exp") == 0) {
+ fCurrentScale = kExp;
+ } else {
+ fCurrentScale = kLin;
+ }
+ } else if (strcmp(key, "unit") == 0) {
+ fCurrentUnit = val;
+ } else if (strcmp(key, "acc") == 0) {
+ fCurrentAcc = val;
+ } else if (strcmp(key, "gyr") == 0) {
+ fCurrentGyr = val;
+ } else if (strcmp(key, "screencolor") == 0) {
+ fCurrentColor = val; // val = "red", "green", "blue" or "white"
+ } else if (strcmp(key, "tooltip") == 0) {
+ fCurrentTooltip = val;
+ }
+ }
+
+ virtual void declare(const char* key, const char* val)
+ {}
+
+ //-------------------------------------------------------------------------------
+ // Simple API part
+ //-------------------------------------------------------------------------------
+ int getParamsCount() { return fNumParameters; }
+ int getParamIndex(const char* path)
+ {
+ if (fPathMap.find(path) != fPathMap.end()) {
+ return fPathMap[path];
+ } else if (fLabelMap.find(path) != fLabelMap.end()) {
+ return fLabelMap[path];
+ } else {
+ return -1;
+ }
+ }
+ const char* getParamAddress(int p) { return fPaths[p].c_str(); }
+ const char* getParamLabel(int p) { return fLabels[p].c_str(); }
+ std::map<const char*, const char*> getMetadata(int p)
+ {
+ std::map<const char*, const char*> res;
+ std::map<std::string, std::string> metadata = fMetaData[p];
+ for (auto it : metadata) {
+ res[it.first.c_str()] = it.second.c_str();
+ }
+ return res;
+ }
+
+ const char* getMetadata(int p, const char* key)
+ {
+ return (fMetaData[p].find(key) != fMetaData[p].end()) ? fMetaData[p][key].c_str() : "";
+ }
+ FAUSTFLOAT getParamMin(int p) { return fMin[p]; }
+ FAUSTFLOAT getParamMax(int p) { return fMax[p]; }
+ FAUSTFLOAT getParamStep(int p) { return fStep[p]; }
+ FAUSTFLOAT getParamInit(int p) { return fInit[p]; }
+
+ FAUSTFLOAT* getParamZone(int p) { return fZone[p]; }
+ FAUSTFLOAT getParamValue(int p) { return *fZone[p]; }
+ void setParamValue(int p, FAUSTFLOAT v) { *fZone[p] = v; }
+
+ double getParamRatio(int p) { return fConversion[p]->faust2ui(*fZone[p]); }
+ void setParamRatio(int p, double r) { *fZone[p] = fConversion[p]->ui2faust(r); }
+
+ double value2ratio(int p, double r) { return fConversion[p]->faust2ui(r); }
+ double ratio2value(int p, double r) { return fConversion[p]->ui2faust(r); }
+
+ /**
+ * Return the control type (kAcc, kGyr, or -1) for a given parameter
+ *
+ * @param p - the UI parameter index
+ *
+ * @return the type
+ */
+ Type getParamType(int p)
+ {
+ if (p >= 0) {
+ if (getZoneIndex(fAcc, p, 0) != -1
+ || getZoneIndex(fAcc, p, 1) != -1
+ || getZoneIndex(fAcc, p, 2) != -1) {
+ return kAcc;
+ } else if (getZoneIndex(fGyr, p, 0) != -1
+ || getZoneIndex(fGyr, p, 1) != -1
+ || getZoneIndex(fGyr, p, 2) != -1) {
+ return kGyr;
+ }
+ }
+ return kNoType;
+ }
+
+ /**
+ * Return the Item type (kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry, kHBargraph, kVBargraph) for a given parameter
+ *
+ * @param p - the UI parameter index
+ *
+ * @return the Item type
+ */
+ ItemType getParamItemType(int p)
+ {
+ return fItemType[p];
+ }
+
+ /**
+ * Set a new value coming from an accelerometer, propagate it to all relevant FAUSTFLOAT* zones.
+ *
+ * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+ * @param value - the new value
+ *
+ */
+ void propagateAcc(int acc, double value)
+ {
+ for (size_t i = 0; i < fAcc[acc].size(); i++) {
+ fAcc[acc][i]->update(value);
+ }
+ }
+
+ /**
+ * Used to edit accelerometer curves and mapping. Set curve and related mapping for a given UI parameter.
+ *
+ * @param p - the UI parameter index
+ * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer (-1 means "no mapping")
+ * @param curve - between 0 and 3
+ * @param amin - mapping 'min' point
+ * @param amid - mapping 'middle' point
+ * @param amax - mapping 'max' point
+ *
+ */
+ void setAccConverter(int p, int acc, int curve, double amin, double amid, double amax)
+ {
+ setConverter(fAcc, p, acc, curve, amin, amid, amax);
+ }
+
+ /**
+ * Used to edit gyroscope curves and mapping. Set curve and related mapping for a given UI parameter.
+ *
+ * @param p - the UI parameter index
+ * @param acc - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope (-1 means "no mapping")
+ * @param curve - between 0 and 3
+ * @param amin - mapping 'min' point
+ * @param amid - mapping 'middle' point
+ * @param amax - mapping 'max' point
+ *
+ */
+ void setGyrConverter(int p, int gyr, int curve, double amin, double amid, double amax)
+ {
+ setConverter(fGyr, p, gyr, curve, amin, amid, amax);
+ }
+
+ /**
+ * Used to edit accelerometer curves and mapping. Get curve and related mapping for a given UI parameter.
+ *
+ * @param p - the UI parameter index
+ * @param acc - the acc value to be retrieved (-1 means "no mapping")
+ * @param curve - the curve value to be retrieved
+ * @param amin - the amin value to be retrieved
+ * @param amid - the amid value to be retrieved
+ * @param amax - the amax value to be retrieved
+ *
+ */
+ void getAccConverter(int p, int& acc, int& curve, double& amin, double& amid, double& amax)
+ {
+ getConverter(fAcc, p, acc, curve, amin, amid, amax);
+ }
+
+ /**
+ * Used to edit gyroscope curves and mapping. Get curve and related mapping for a given UI parameter.
+ *
+ * @param p - the UI parameter index
+ * @param gyr - the gyr value to be retrieved (-1 means "no mapping")
+ * @param curve - the curve value to be retrieved
+ * @param amin - the amin value to be retrieved
+ * @param amid - the amid value to be retrieved
+ * @param amax - the amax value to be retrieved
+ *
+ */
+ void getGyrConverter(int p, int& gyr, int& curve, double& amin, double& amid, double& amax)
+ {
+ getConverter(fGyr, p, gyr, curve, amin, amid, amax);
+ }
+
+ /**
+ * Set a new value coming from an gyroscope, propagate it to all relevant FAUSTFLOAT* zones.
+ *
+ * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
+ * @param value - the new value
+ *
+ */
+ void propagateGyr(int gyr, double value)
+ {
+ for (size_t i = 0; i < fGyr[gyr].size(); i++) {
+ fGyr[gyr][i]->update(value);
+ }
+ }
+
+ /**
+ * Get the number of FAUSTFLOAT* zones controlled with the accelerometer
+ *
+ * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+ * @return the number of zones
+ *
+ */
+ int getAccCount(int acc)
+ {
+ return (acc >= 0 && acc < 3) ? int(fAcc[acc].size()) : 0;
+ }
+
+ /**
+ * Get the number of FAUSTFLOAT* zones controlled with the gyroscope
+ *
+ * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
+ * @param the number of zones
+ *
+ */
+ int getGyrCount(int gyr)
+ {
+ return (gyr >= 0 && gyr < 3) ? int(fGyr[gyr].size()) : 0;
+ }
+
+ // getScreenColor() : -1 means no screen color control (no screencolor metadata found)
+ // otherwise return 0x00RRGGBB a ready to use color
+ int getScreenColor()
+ {
+ if (fHasScreenControl) {
+ int r = (fRedReader) ? fRedReader->getValue() : 0;
+ int g = (fGreenReader) ? fGreenReader->getValue() : 0;
+ int b = (fBlueReader) ? fBlueReader->getValue() : 0;
+ return (r<<16) | (g<<8) | b;
+ } else {
+ return -1;
+ }
+ }
+
+};
+
+#endif
+/************************** END APIUI.h **************************/
+
+// NOTE: "faust -scn name" changes the last line above to
+// #include <faust/name/name.h>
+
+//----------------------------------------------------------------------------
+// FAUST Generated Code
+//----------------------------------------------------------------------------
+
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+#include <algorithm>
+#include <cmath>
+#include <math.h>
+
+
+#ifndef FAUSTCLASS
+#define FAUSTCLASS limiterdsp
+#endif
+
+#ifdef __APPLE__
+#define exp10f __exp10f
+#define exp10 __exp10
+#endif
+
+class limiterdsp : public dsp {
+
+ private:
+
+ int fSampleRate;
+ float fConst0;
+ float fConst1;
+ float fConst2;
+ float fConst3;
+ int iRec5[2];
+ FAUSTFLOAT fHslider0;
+ int IOTA;
+ float fVec0[32];
+ float fRec4[2];
+ int iRec2[2];
+ float fRec1[2];
+ float fConst4;
+ float fConst5;
+ float fRec0[2];
+ int iConst6;
+
+ public:
+
+ void metadata(Meta* m) {
+ m->declare("analyzers.lib/name", "Faust Analyzer Library");
+ m->declare("analyzers.lib/version", "0.1");
+ m->declare("basics.lib/name", "Faust Basic Element Library");
+ m->declare("basics.lib/version", "0.1");
+ m->declare("compressors.lib/limiter_lad_N:author", "Dario Sanfilippo");
+ m->declare("compressors.lib/limiter_lad_N:copyright", "Copyright (C) 2020 Dario Sanfilippo <sanfilippo.dario@gmail.com>");
+ m->declare("compressors.lib/limiter_lad_N:license", "GPLv3 license");
+ m->declare("compressors.lib/limiter_lad_mono:author", "Dario Sanfilippo");
+ m->declare("compressors.lib/limiter_lad_mono:copyright", "Copyright (C) 2020 Dario Sanfilippo <sanfilippo.dario@gmail.com>");
+ m->declare("compressors.lib/limiter_lad_mono:license", "GPLv3 license");
+ m->declare("compressors.lib/name", "Faust Compressor Effect Library");
+ m->declare("compressors.lib/version", "0.0");
+ m->declare("filename", "limiterdsp.dsp");
+ m->declare("maths.lib/author", "GRAME");
+ m->declare("maths.lib/copyright", "GRAME");
+ m->declare("maths.lib/license", "LGPL with exception");
+ m->declare("maths.lib/name", "Faust Math Library");
+ m->declare("maths.lib/version", "2.3");
+ m->declare("name", "limiterdsp");
+ m->declare("platform.lib/name", "Generic Platform Library");
+ m->declare("platform.lib/version", "0.1");
+ m->declare("routes.lib/name", "Faust Signal Routing Library");
+ m->declare("routes.lib/version", "0.2");
+ m->declare("signals.lib/name", "Faust Signal Routing Library");
+ m->declare("signals.lib/version", "0.0");
+ }
+
+ virtual int getNumInputs() {
+ return 1;
+ }
+ virtual int getNumOutputs() {
+ return 1;
+ }
+ virtual int getInputRate(int channel) {
+ int rate;
+ switch ((channel)) {
+ case 0: {
+ rate = 1;
+ break;
+ }
+ default: {
+ rate = -1;
+ break;
+ }
+ }
+ return rate;
+ }
+ virtual int getOutputRate(int channel) {
+ int rate;
+ switch ((channel)) {
+ case 0: {
+ rate = 1;
+ break;
+ }
+ default: {
+ rate = -1;
+ break;
+ }
+ }
+ return rate;
+ }
+
+ static void classInit(int sample_rate) {
+ }
+
+ virtual void instanceConstants(int sample_rate) {
+ fSampleRate = sample_rate;
+ fConst0 = std::min<float>(192000.0f, std::max<float>(1.0f, float(fSampleRate)));
+ fConst1 = std::exp((0.0f - (100000.0f / fConst0)));
+ fConst2 = (1.0f - fConst1);
+ fConst3 = (0.100000001f * fConst0);
+ fConst4 = std::exp((0.0f - (4.0f / fConst0)));
+ fConst5 = (1.0f - fConst4);
+ iConst6 = int((9.99999975e-05f * fConst0));
+ }
+
+ virtual void instanceResetUserInterface() {
+ fHslider0 = FAUSTFLOAT(2.0f);
+ }
+
+ virtual void instanceClear() {
+ for (int l0 = 0; (l0 < 2); l0 = (l0 + 1)) {
+ iRec5[l0] = 0;
+ }
+ IOTA = 0;
+ for (int l1 = 0; (l1 < 32); l1 = (l1 + 1)) {
+ fVec0[l1] = 0.0f;
+ }
+ for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) {
+ fRec4[l2] = 0.0f;
+ }
+ for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) {
+ iRec2[l3] = 0;
+ }
+ for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) {
+ fRec1[l4] = 0.0f;
+ }
+ for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) {
+ fRec0[l5] = 0.0f;
+ }
+ }
+
+ virtual void init(int sample_rate) {
+ classInit(sample_rate);
+ instanceInit(sample_rate);
+ }
+ virtual void instanceInit(int sample_rate) {
+ instanceConstants(sample_rate);
+ instanceResetUserInterface();
+ instanceClear();
+ }
+
+ virtual limiterdsp* clone() {
+ return new limiterdsp();
+ }
+
+ virtual int getSampleRate() {
+ return fSampleRate;
+ }
+
+ virtual void buildUserInterface(UI* ui_interface) {
+ ui_interface->openVerticalBox("limiterdsp");
+ ui_interface->declare(&fHslider0, "0", "");
+ ui_interface->addHorizontalSlider("NumClientsAssumed", &fHslider0, 2.0f, 1.0f, 64.0f, 1.0f);
+ ui_interface->closeBox();
+ }
+
+ virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
+ FAUSTFLOAT* input0 = inputs[0];
+ FAUSTFLOAT* output0 = outputs[0];
+ float fSlow0 = (1.0f / std::sqrt(float(fHslider0)));
+ for (int i = 0; (i < count); i = (i + 1)) {
+ float fTemp0 = float(input0[i]);
+ iRec5[0] = ((iRec5[1] + 1) % int(std::max<float>(1.0f, (fConst3 * float(iRec2[1])))));
+ float fTemp1 = (fSlow0 * fTemp0);
+ fVec0[(IOTA & 31)] = fTemp1;
+ float fTemp2 = std::fabs(fTemp1);
+ fRec4[0] = std::max<float>((float((iRec5[0] > 0)) * fRec4[1]), fTemp2);
+ iRec2[0] = (fRec4[0] >= fTemp2);
+ float fRec3 = fRec4[0];
+ fRec1[0] = ((fConst1 * fRec1[1]) + (fConst2 * fRec3));
+ float fTemp3 = std::fabs(fRec1[0]);
+ fRec0[0] = std::max<float>(fTemp3, ((fConst4 * fRec0[1]) + (fConst5 * fTemp3)));
+ output0[i] = FAUSTFLOAT((std::min<float>(1.0f, (0.5f / std::max<float>(fRec0[0], 1.1920929e-07f))) * fVec0[((IOTA - iConst6) & 31)]));
+ iRec5[1] = iRec5[0];
+ IOTA = (IOTA + 1);
+ fRec4[1] = fRec4[0];
+ iRec2[1] = iRec2[0];
+ fRec1[1] = fRec1[0];
+ fRec0[1] = fRec0[0];
+ }
+ }
+
+};
+
+#endif
diff --git a/src/makeXcodeproj.sh b/src/makeXcodeproj.sh
new file mode 100755
index 0000000..c1dcf31
--- /dev/null
+++ b/src/makeXcodeproj.sh
@@ -0,0 +1 @@
+qmake -spec macx-xcode jacktrip.pro
diff --git a/src/zitarevdsp.h b/src/zitarevdsp.h
new file mode 100644
index 0000000..96067d4
--- /dev/null
+++ b/src/zitarevdsp.h
@@ -0,0 +1,2375 @@
+/* ------------------------------------------------------------
+name: "zitarevdsp"
+Code generated with Faust 2.28.6 (https://faust.grame.fr)
+Compilation options: -lang cpp -inpl -scal -ftz 0
+------------------------------------------------------------ */
+
+#ifndef __zitarevdsp_H__
+#define __zitarevdsp_H__
+
+// NOTE: ANY INCLUDE-GUARD HERE MUST BE DERIVED FROM THE CLASS NAME
+//
+// faust2header.cpp - FAUST Architecture File
+// This is a simple variation of matlabplot.cpp in the Faust distribution
+// aimed at creating a simple C++ header file (.h) containing a Faust DSP.
+// See the Makefile for how to use it.
+
+/************************** BEGIN dsp.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __dsp__
+#define __dsp__
+
+#include <string>
+#include <vector>
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+struct UI;
+struct Meta;
+
+/**
+ * DSP memory manager.
+ */
+
+struct dsp_memory_manager {
+
+ virtual ~dsp_memory_manager() {}
+
+ virtual void* allocate(size_t size) = 0;
+ virtual void destroy(void* ptr) = 0;
+
+};
+
+/**
+* Signal processor definition.
+*/
+
+class dsp {
+
+ public:
+
+ dsp() {}
+ virtual ~dsp() {}
+
+ /* Return instance number of audio inputs */
+ virtual int getNumInputs() = 0;
+
+ /* Return instance number of audio outputs */
+ virtual int getNumOutputs() = 0;
+
+ /**
+ * Trigger the ui_interface parameter with instance specific calls
+ * to 'openTabBox', 'addButton', 'addVerticalSlider'... in order to build the UI.
+ *
+ * @param ui_interface - the user interface builder
+ */
+ virtual void buildUserInterface(UI* ui_interface) = 0;
+
+ /* Returns the sample rate currently used by the instance */
+ virtual int getSampleRate() = 0;
+
+ /**
+ * Global init, calls the following methods:
+ * - static class 'classInit': static tables initialization
+ * - 'instanceInit': constants and instance state initialization
+ *
+ * @param sample_rate - the sampling rate in Hertz
+ */
+ virtual void init(int sample_rate) = 0;
+
+ /**
+ * Init instance state
+ *
+ * @param sample_rate - the sampling rate in Hertz
+ */
+ virtual void instanceInit(int sample_rate) = 0;
+
+ /**
+ * Init instance constant state
+ *
+ * @param sample_rate - the sampling rate in Hertz
+ */
+ virtual void instanceConstants(int sample_rate) = 0;
+
+ /* Init default control parameters values */
+ virtual void instanceResetUserInterface() = 0;
+
+ /* Init instance state (delay lines...) */
+ virtual void instanceClear() = 0;
+
+ /**
+ * Return a clone of the instance.
+ *
+ * @return a copy of the instance on success, otherwise a null pointer.
+ */
+ virtual dsp* clone() = 0;
+
+ /**
+ * Trigger the Meta* parameter with instance specific calls to 'declare' (key, value) metadata.
+ *
+ * @param m - the Meta* meta user
+ */
+ virtual void metadata(Meta* m) = 0;
+
+ /**
+ * DSP instance computation, to be called with successive in/out audio buffers.
+ *
+ * @param count - the number of frames to compute
+ * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
+ * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
+ *
+ */
+ virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) = 0;
+
+ /**
+ * DSP instance computation: alternative method to be used by subclasses.
+ *
+ * @param date_usec - the timestamp in microsec given by audio driver.
+ * @param count - the number of frames to compute
+ * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
+ * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
+ *
+ */
+ virtual void compute(double /*date_usec*/, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { compute(count, inputs, outputs); }
+
+};
+
+/**
+ * Generic DSP decorator.
+ */
+
+class decorator_dsp : public dsp {
+
+ protected:
+
+ dsp* fDSP;
+
+ public:
+
+ decorator_dsp(dsp* dsp = nullptr):fDSP(dsp) {}
+ virtual ~decorator_dsp() { delete fDSP; }
+
+ virtual int getNumInputs() { return fDSP->getNumInputs(); }
+ virtual int getNumOutputs() { return fDSP->getNumOutputs(); }
+ virtual void buildUserInterface(UI* ui_interface) { fDSP->buildUserInterface(ui_interface); }
+ virtual int getSampleRate() { return fDSP->getSampleRate(); }
+ virtual void init(int sample_rate) { fDSP->init(sample_rate); }
+ virtual void instanceInit(int sample_rate) { fDSP->instanceInit(sample_rate); }
+ virtual void instanceConstants(int sample_rate) { fDSP->instanceConstants(sample_rate); }
+ virtual void instanceResetUserInterface() { fDSP->instanceResetUserInterface(); }
+ virtual void instanceClear() { fDSP->instanceClear(); }
+ virtual decorator_dsp* clone() { return new decorator_dsp(fDSP->clone()); }
+ virtual void metadata(Meta* m) { fDSP->metadata(m); }
+ // Beware: subclasses usually have to overload the two 'compute' methods
+ virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(count, inputs, outputs); }
+ virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(date_usec, count, inputs, outputs); }
+
+};
+
+/**
+ * DSP factory class.
+ */
+
+class dsp_factory {
+
+ protected:
+
+ // So that to force sub-classes to use deleteDSPFactory(dsp_factory* factory);
+ virtual ~dsp_factory() {}
+
+ public:
+
+ virtual std::string getName() = 0;
+ virtual std::string getSHAKey() = 0;
+ virtual std::string getDSPCode() = 0;
+ virtual std::string getCompileOptions() = 0;
+ virtual std::vector<std::string> getLibraryList() = 0;
+ virtual std::vector<std::string> getIncludePathnames() = 0;
+
+ virtual dsp* createDSPInstance() = 0;
+
+ virtual void setMemoryManager(dsp_memory_manager* manager) = 0;
+ virtual dsp_memory_manager* getMemoryManager() = 0;
+
+};
+
+/**
+ * On Intel set FZ (Flush to Zero) and DAZ (Denormals Are Zero)
+ * flags to avoid costly denormals.
+ */
+
+#ifdef __SSE__
+ #include <xmmintrin.h>
+ #ifdef __SSE2__
+ #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
+ #else
+ #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
+ #endif
+#else
+ #define AVOIDDENORMALS
+#endif
+
+#endif
+/************************** END dsp.h **************************/
+
+/************************** BEGIN APIUI.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef API_UI_H
+#define API_UI_H
+
+#include <sstream>
+#include <string>
+#include <vector>
+#include <iostream>
+#include <map>
+
+/************************** BEGIN meta.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __meta__
+#define __meta__
+
+struct Meta
+{
+ virtual ~Meta() {};
+ virtual void declare(const char* key, const char* value) = 0;
+
+};
+
+#endif
+/************************** END meta.h **************************/
+/************************** BEGIN UI.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2020 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __UI_H__
+#define __UI_H__
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+/*******************************************************************************
+ * UI : Faust DSP User Interface
+ * User Interface as expected by the buildUserInterface() method of a DSP.
+ * This abstract class contains only the method that the Faust compiler can
+ * generate to describe a DSP user interface.
+ ******************************************************************************/
+
+struct Soundfile;
+
+template <typename REAL>
+struct UIReal
+{
+ UIReal() {}
+ virtual ~UIReal() {}
+
+ // -- widget's layouts
+
+ virtual void openTabBox(const char* label) = 0;
+ virtual void openHorizontalBox(const char* label) = 0;
+ virtual void openVerticalBox(const char* label) = 0;
+ virtual void closeBox() = 0;
+
+ // -- active widgets
+
+ virtual void addButton(const char* label, REAL* zone) = 0;
+ virtual void addCheckButton(const char* label, REAL* zone) = 0;
+ virtual void addVerticalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
+ virtual void addHorizontalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
+ virtual void addNumEntry(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
+
+ // -- passive widgets
+
+ virtual void addHorizontalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
+ virtual void addVerticalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
+
+ // -- soundfiles
+
+ virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) = 0;
+
+ // -- metadata declarations
+
+ virtual void declare(REAL* zone, const char* key, const char* val) {}
+};
+
+struct UI : public UIReal<FAUSTFLOAT>
+{
+ UI() {}
+ virtual ~UI() {}
+};
+
+#endif
+/************************** END UI.h **************************/
+/************************** BEGIN PathBuilder.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef FAUST_PATHBUILDER_H
+#define FAUST_PATHBUILDER_H
+
+#include <vector>
+#include <string>
+#include <algorithm>
+
+/*******************************************************************************
+ * PathBuilder : Faust User Interface
+ * Helper class to build complete hierarchical path for UI items.
+ ******************************************************************************/
+
+class PathBuilder
+{
+
+ protected:
+
+ std::vector<std::string> fControlsLevel;
+
+ public:
+
+ PathBuilder() {}
+ virtual ~PathBuilder() {}
+
+ std::string buildPath(const std::string& label)
+ {
+ std::string res = "/";
+ for (size_t i = 0; i < fControlsLevel.size(); i++) {
+ res += fControlsLevel[i];
+ res += "/";
+ }
+ res += label;
+ std::replace(res.begin(), res.end(), ' ', '_');
+ return res;
+ }
+
+ std::string buildLabel(std::string label)
+ {
+ std::replace(label.begin(), label.end(), ' ', '_');
+ return label;
+ }
+
+ void pushLabel(const std::string& label) { fControlsLevel.push_back(label); }
+ void popLabel() { fControlsLevel.pop_back(); }
+
+};
+
+#endif // FAUST_PATHBUILDER_H
+/************************** END PathBuilder.h **************************/
+/************************** BEGIN ValueConverter.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __ValueConverter__
+#define __ValueConverter__
+
+/***************************************************************************************
+ ValueConverter.h
+ (GRAME, Copyright 2015-2019)
+
+Set of conversion objects used to map user interface values (for example a gui slider
+delivering values between 0 and 1) to faust values (for example a vslider between
+20 and 20000) using a log scale.
+
+-- Utilities
+
+Range(lo,hi) : clip a value x between lo and hi
+Interpolator(lo,hi,v1,v2) : Maps a value x between lo and hi to a value y between v1 and v2
+Interpolator3pt(lo,mi,hi,v1,vm,v2) : Map values between lo mid hi to values between v1 vm v2
+
+-- Value Converters
+
+ValueConverter::ui2faust(x)
+ValueConverter::faust2ui(x)
+
+-- ValueConverters used for sliders depending of the scale
+
+LinearValueConverter(umin, umax, fmin, fmax)
+LinearValueConverter2(lo, mi, hi, v1, vm, v2) using 2 segments
+LogValueConverter(umin, umax, fmin, fmax)
+ExpValueConverter(umin, umax, fmin, fmax)
+
+-- ValueConverters used for accelerometers based on 3 points
+
+AccUpConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 0
+AccDownConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 1
+AccUpDownConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 2
+AccDownUpConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 3
+
+-- lists of ZoneControl are used to implement accelerometers metadata for each axes
+
+ZoneControl(zone, valueConverter) : a zone with an accelerometer data converter
+
+-- ZoneReader are used to implement screencolor metadata
+
+ZoneReader(zone, valueConverter) : a zone with a data converter
+
+****************************************************************************************/
+
+#include <float.h>
+#include <algorithm> // std::max
+#include <cmath>
+#include <vector>
+#include <assert.h>
+
+//--------------------------------------------------------------------------------------
+// Interpolator(lo,hi,v1,v2)
+// Maps a value x between lo and hi to a value y between v1 and v2
+// y = v1 + (x-lo)/(hi-lo)*(v2-v1)
+// y = v1 + (x-lo) * coef with coef = (v2-v1)/(hi-lo)
+// y = v1 + x*coef - lo*coef
+// y = v1 - lo*coef + x*coef
+// y = offset + x*coef with offset = v1 - lo*coef
+//--------------------------------------------------------------------------------------
+class Interpolator
+{
+ private:
+
+ //--------------------------------------------------------------------------------------
+ // Range(lo,hi) clip a value between lo and hi
+ //--------------------------------------------------------------------------------------
+ struct Range
+ {
+ double fLo;
+ double fHi;
+
+ Range(double x, double y) : fLo(std::min<double>(x,y)), fHi(std::max<double>(x,y)) {}
+ double operator()(double x) { return (x<fLo) ? fLo : (x>fHi) ? fHi : x; }
+ };
+
+
+ Range fRange;
+ double fCoef;
+ double fOffset;
+
+ public:
+
+ Interpolator(double lo, double hi, double v1, double v2) : fRange(lo,hi)
+ {
+ if (hi != lo) {
+ // regular case
+ fCoef = (v2-v1)/(hi-lo);
+ fOffset = v1 - lo*fCoef;
+ } else {
+ // degenerate case, avoids division by zero
+ fCoef = 0;
+ fOffset = (v1+v2)/2;
+ }
+ }
+ double operator()(double v)
+ {
+ double x = fRange(v);
+ return fOffset + x*fCoef;
+ }
+
+ void getLowHigh(double& amin, double& amax)
+ {
+ amin = fRange.fLo;
+ amax = fRange.fHi;
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Interpolator3pt(lo,mi,hi,v1,vm,v2)
+// Map values between lo mid hi to values between v1 vm v2
+//--------------------------------------------------------------------------------------
+class Interpolator3pt
+{
+
+ private:
+
+ Interpolator fSegment1;
+ Interpolator fSegment2;
+ double fMid;
+
+ public:
+
+ Interpolator3pt(double lo, double mi, double hi, double v1, double vm, double v2) :
+ fSegment1(lo, mi, v1, vm),
+ fSegment2(mi, hi, vm, v2),
+ fMid(mi) {}
+ double operator()(double x) { return (x < fMid) ? fSegment1(x) : fSegment2(x); }
+
+ void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fSegment1.getLowHigh(amin, amid);
+ fSegment2.getLowHigh(amid, amax);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Abstract ValueConverter class. Converts values between UI and Faust representations
+//--------------------------------------------------------------------------------------
+class ValueConverter
+{
+
+ public:
+
+ virtual ~ValueConverter() {}
+ virtual double ui2faust(double x) = 0;
+ virtual double faust2ui(double x) = 0;
+};
+
+//--------------------------------------------------------------------------------------
+// A converter than can be updated
+//--------------------------------------------------------------------------------------
+
+class UpdatableValueConverter : public ValueConverter {
+
+ protected:
+
+ bool fActive;
+
+ public:
+
+ UpdatableValueConverter():fActive(true)
+ {}
+ virtual ~UpdatableValueConverter()
+ {}
+
+ virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max) = 0;
+ virtual void getMappingValues(double& amin, double& amid, double& amax) = 0;
+
+ void setActive(bool on_off) { fActive = on_off; }
+ bool getActive() { return fActive; }
+
+};
+
+
+//--------------------------------------------------------------------------------------
+// Linear conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class LinearValueConverter : public ValueConverter
+{
+
+ private:
+
+ Interpolator fUI2F;
+ Interpolator fF2UI;
+
+ public:
+
+ LinearValueConverter(double umin, double umax, double fmin, double fmax) :
+ fUI2F(umin,umax,fmin,fmax), fF2UI(fmin,fmax,umin,umax)
+ {}
+
+ LinearValueConverter() : fUI2F(0.,0.,0.,0.), fF2UI(0.,0.,0.,0.)
+ {}
+ virtual double ui2faust(double x) { return fUI2F(x); }
+ virtual double faust2ui(double x) { return fF2UI(x); }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Two segments linear conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class LinearValueConverter2 : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fUI2F;
+ Interpolator3pt fF2UI;
+
+ public:
+
+ LinearValueConverter2(double amin, double amid, double amax, double min, double init, double max) :
+ fUI2F(amin, amid, amax, min, init, max), fF2UI(min, init, max, amin, amid, amax)
+ {}
+
+ LinearValueConverter2() : fUI2F(0.,0.,0.,0.,0.,0.), fF2UI(0.,0.,0.,0.,0.,0.)
+ {}
+
+ virtual double ui2faust(double x) { return fUI2F(x); }
+ virtual double faust2ui(double x) { return fF2UI(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max)
+ {
+ fUI2F = Interpolator3pt(amin, amid, amax, min, init, max);
+ fF2UI = Interpolator3pt(min, init, max, amin, amid, amax);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fUI2F.getMappingValues(amin, amid, amax);
+ }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Logarithmic conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class LogValueConverter : public LinearValueConverter
+{
+
+ public:
+
+ LogValueConverter(double umin, double umax, double fmin, double fmax) :
+ LinearValueConverter(umin, umax, std::log(std::max<double>(DBL_MIN, fmin)), std::log(std::max<double>(DBL_MIN, fmax)))
+ {}
+
+ virtual double ui2faust(double x) { return std::exp(LinearValueConverter::ui2faust(x)); }
+ virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::log(std::max<double>(x, DBL_MIN))); }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Exponential conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class ExpValueConverter : public LinearValueConverter
+{
+
+ public:
+
+ ExpValueConverter(double umin, double umax, double fmin, double fmax) :
+ LinearValueConverter(umin, umax, std::min<double>(DBL_MAX, std::exp(fmin)), std::min<double>(DBL_MAX, std::exp(fmax)))
+ {}
+
+ virtual double ui2faust(double x) { return std::log(LinearValueConverter::ui2faust(x)); }
+ virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::min<double>(DBL_MAX, std::exp(x))); }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using an Up curve (curve 0)
+//--------------------------------------------------------------------------------------
+class AccUpConverter : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fA2F;
+ Interpolator3pt fF2A;
+
+ public:
+
+ AccUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
+ fA2F(amin,amid,amax,fmin,fmid,fmax),
+ fF2A(fmin,fmid,fmax,amin,amid,amax)
+ {}
+
+ virtual double ui2faust(double x) { return fA2F(x); }
+ virtual double faust2ui(double x) { return fF2A(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
+ {
+ //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+ fA2F = Interpolator3pt(amin, amid, amax, fmin, fmid, fmax);
+ fF2A = Interpolator3pt(fmin, fmid, fmax, amin, amid, amax);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fA2F.getMappingValues(amin, amid, amax);
+ }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using a Down curve (curve 1)
+//--------------------------------------------------------------------------------------
+class AccDownConverter : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fA2F;
+ Interpolator3pt fF2A;
+
+ public:
+
+ AccDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
+ fA2F(amin,amid,amax,fmax,fmid,fmin),
+ fF2A(fmin,fmid,fmax,amax,amid,amin)
+ {}
+
+ virtual double ui2faust(double x) { return fA2F(x); }
+ virtual double faust2ui(double x) { return fF2A(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
+ {
+ //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+ fA2F = Interpolator3pt(amin, amid, amax, fmax, fmid, fmin);
+ fF2A = Interpolator3pt(fmin, fmid, fmax, amax, amid, amin);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fA2F.getMappingValues(amin, amid, amax);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using an Up-Down curve (curve 2)
+//--------------------------------------------------------------------------------------
+class AccUpDownConverter : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fA2F;
+ Interpolator fF2A;
+
+ public:
+
+ AccUpDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
+ fA2F(amin,amid,amax,fmin,fmax,fmin),
+ fF2A(fmin,fmax,amin,amax) // Special, pseudo inverse of a non monotonic function
+ {}
+
+ virtual double ui2faust(double x) { return fA2F(x); }
+ virtual double faust2ui(double x) { return fF2A(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
+ {
+ //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+ fA2F = Interpolator3pt(amin, amid, amax, fmin, fmax, fmin);
+ fF2A = Interpolator(fmin, fmax, amin, amax);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fA2F.getMappingValues(amin, amid, amax);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using a Down-Up curve (curve 3)
+//--------------------------------------------------------------------------------------
+class AccDownUpConverter : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fA2F;
+ Interpolator fF2A;
+
+ public:
+
+ AccDownUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
+ fA2F(amin,amid,amax,fmax,fmin,fmax),
+ fF2A(fmin,fmax,amin,amax) // Special, pseudo inverse of a non monotonic function
+ {}
+
+ virtual double ui2faust(double x) { return fA2F(x); }
+ virtual double faust2ui(double x) { return fF2A(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
+ {
+ //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+ fA2F = Interpolator3pt(amin, amid, amax, fmax, fmin, fmax);
+ fF2A = Interpolator(fmin, fmax, amin, amax);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fA2F.getMappingValues(amin, amid, amax);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Base class for ZoneControl
+//--------------------------------------------------------------------------------------
+class ZoneControl
+{
+
+ protected:
+
+ FAUSTFLOAT* fZone;
+
+ public:
+
+ ZoneControl(FAUSTFLOAT* zone) : fZone(zone) {}
+ virtual ~ZoneControl() {}
+
+ virtual void update(double v) const {}
+
+ virtual void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max) {}
+ virtual void getMappingValues(double& amin, double& amid, double& amax) {}
+
+ FAUSTFLOAT* getZone() { return fZone; }
+
+ virtual void setActive(bool on_off) {}
+ virtual bool getActive() { return false; }
+
+ virtual int getCurve() { return -1; }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Useful to implement accelerometers metadata as a list of ZoneControl for each axes
+//--------------------------------------------------------------------------------------
+class ConverterZoneControl : public ZoneControl
+{
+
+ protected:
+
+ ValueConverter* fValueConverter;
+
+ public:
+
+ ConverterZoneControl(FAUSTFLOAT* zone, ValueConverter* converter) : ZoneControl(zone), fValueConverter(converter) {}
+ virtual ~ConverterZoneControl() { delete fValueConverter; } // Assuming fValueConverter is not kept elsewhere...
+
+ virtual void update(double v) const { *fZone = fValueConverter->ui2faust(v); }
+
+ ValueConverter* getConverter() { return fValueConverter; }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Association of a zone and a four value converter, each one for each possible curve.
+// Useful to implement accelerometers metadata as a list of ZoneControl for each axes
+//--------------------------------------------------------------------------------------
+class CurveZoneControl : public ZoneControl
+{
+
+ private:
+
+ std::vector<UpdatableValueConverter*> fValueConverters;
+ int fCurve;
+
+ public:
+
+ CurveZoneControl(FAUSTFLOAT* zone, int curve, double amin, double amid, double amax, double min, double init, double max) : ZoneControl(zone), fCurve(0)
+ {
+ assert(curve >= 0 && curve <= 3);
+ fValueConverters.push_back(new AccUpConverter(amin, amid, amax, min, init, max));
+ fValueConverters.push_back(new AccDownConverter(amin, amid, amax, min, init, max));
+ fValueConverters.push_back(new AccUpDownConverter(amin, amid, amax, min, init, max));
+ fValueConverters.push_back(new AccDownUpConverter(amin, amid, amax, min, init, max));
+ fCurve = curve;
+ }
+ virtual ~CurveZoneControl()
+ {
+ std::vector<UpdatableValueConverter*>::iterator it;
+ for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
+ delete(*it);
+ }
+ }
+ void update(double v) const { if (fValueConverters[fCurve]->getActive()) *fZone = fValueConverters[fCurve]->ui2faust(v); }
+
+ void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max)
+ {
+ fValueConverters[curve]->setMappingValues(amin, amid, amax, min, init, max);
+ fCurve = curve;
+ }
+
+ void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fValueConverters[fCurve]->getMappingValues(amin, amid, amax);
+ }
+
+ void setActive(bool on_off)
+ {
+ std::vector<UpdatableValueConverter*>::iterator it;
+ for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
+ (*it)->setActive(on_off);
+ }
+ }
+
+ int getCurve() { return fCurve; }
+};
+
+class ZoneReader
+{
+
+ private:
+
+ FAUSTFLOAT* fZone;
+ Interpolator fInterpolator;
+
+ public:
+
+ ZoneReader(FAUSTFLOAT* zone, double lo, double hi) : fZone(zone), fInterpolator(lo, hi, 0, 255) {}
+
+ virtual ~ZoneReader() {}
+
+ int getValue()
+ {
+ return (fZone != nullptr) ? int(fInterpolator(*fZone)) : 127;
+ }
+
+};
+
+#endif
+/************************** END ValueConverter.h **************************/
+
+class APIUI : public PathBuilder, public Meta, public UI
+{
+ public:
+
+ enum ItemType { kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry, kHBargraph, kVBargraph };
+
+ protected:
+
+ enum { kLin = 0, kLog = 1, kExp = 2 };
+
+ int fNumParameters;
+ std::vector<std::string> fPaths;
+ std::vector<std::string> fLabels;
+ std::map<std::string, int> fPathMap;
+ std::map<std::string, int> fLabelMap;
+ std::vector<ValueConverter*> fConversion;
+ std::vector<FAUSTFLOAT*> fZone;
+ std::vector<FAUSTFLOAT> fInit;
+ std::vector<FAUSTFLOAT> fMin;
+ std::vector<FAUSTFLOAT> fMax;
+ std::vector<FAUSTFLOAT> fStep;
+ std::vector<ItemType> fItemType;
+ std::vector<std::map<std::string, std::string> > fMetaData;
+ std::vector<ZoneControl*> fAcc[3];
+ std::vector<ZoneControl*> fGyr[3];
+
+ // Screen color control
+ // "...[screencolor:red]..." etc.
+ bool fHasScreenControl; // true if control screen color metadata
+ ZoneReader* fRedReader;
+ ZoneReader* fGreenReader;
+ ZoneReader* fBlueReader;
+
+ // Current values controlled by metadata
+ std::string fCurrentUnit;
+ int fCurrentScale;
+ std::string fCurrentAcc;
+ std::string fCurrentGyr;
+ std::string fCurrentColor;
+ std::string fCurrentTooltip;
+ std::map<std::string, std::string> fCurrentMetadata;
+
+ // Add a generic parameter
+ virtual void addParameter(const char* label,
+ FAUSTFLOAT* zone,
+ FAUSTFLOAT init,
+ FAUSTFLOAT min,
+ FAUSTFLOAT max,
+ FAUSTFLOAT step,
+ ItemType type)
+ {
+ std::string path = buildPath(label);
+ fPathMap[path] = fLabelMap[label] = fNumParameters++;
+ fPaths.push_back(path);
+ fLabels.push_back(label);
+ fZone.push_back(zone);
+ fInit.push_back(init);
+ fMin.push_back(min);
+ fMax.push_back(max);
+ fStep.push_back(step);
+ fItemType.push_back(type);
+
+ // handle scale metadata
+ switch (fCurrentScale) {
+ case kLin:
+ fConversion.push_back(new LinearValueConverter(0, 1, min, max));
+ break;
+ case kLog:
+ fConversion.push_back(new LogValueConverter(0, 1, min, max));
+ break;
+ case kExp: fConversion.push_back(new ExpValueConverter(0, 1, min, max));
+ break;
+ }
+ fCurrentScale = kLin;
+
+ if (fCurrentAcc.size() > 0 && fCurrentGyr.size() > 0) {
+ std::cerr << "warning : 'acc' and 'gyr' metadata used for the same " << label << " parameter !!\n";
+ }
+
+ // handle acc metadata "...[acc : <axe> <curve> <amin> <amid> <amax>]..."
+ if (fCurrentAcc.size() > 0) {
+ std::istringstream iss(fCurrentAcc);
+ int axe, curve;
+ double amin, amid, amax;
+ iss >> axe >> curve >> amin >> amid >> amax;
+
+ if ((0 <= axe) && (axe < 3) &&
+ (0 <= curve) && (curve < 4) &&
+ (amin < amax) && (amin <= amid) && (amid <= amax))
+ {
+ fAcc[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
+ } else {
+ std::cerr << "incorrect acc metadata : " << fCurrentAcc << std::endl;
+ }
+ fCurrentAcc = "";
+ }
+
+ // handle gyr metadata "...[gyr : <axe> <curve> <amin> <amid> <amax>]..."
+ if (fCurrentGyr.size() > 0) {
+ std::istringstream iss(fCurrentGyr);
+ int axe, curve;
+ double amin, amid, amax;
+ iss >> axe >> curve >> amin >> amid >> amax;
+
+ if ((0 <= axe) && (axe < 3) &&
+ (0 <= curve) && (curve < 4) &&
+ (amin < amax) && (amin <= amid) && (amid <= amax))
+ {
+ fGyr[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
+ } else {
+ std::cerr << "incorrect gyr metadata : " << fCurrentGyr << std::endl;
+ }
+ fCurrentGyr = "";
+ }
+
+ // handle screencolor metadata "...[screencolor:red|green|blue|white]..."
+ if (fCurrentColor.size() > 0) {
+ if ((fCurrentColor == "red") && (fRedReader == 0)) {
+ fRedReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else if ((fCurrentColor == "green") && (fGreenReader == 0)) {
+ fGreenReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else if ((fCurrentColor == "blue") && (fBlueReader == 0)) {
+ fBlueReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else if ((fCurrentColor == "white") && (fRedReader == 0) && (fGreenReader == 0) && (fBlueReader == 0)) {
+ fRedReader = new ZoneReader(zone, min, max);
+ fGreenReader = new ZoneReader(zone, min, max);
+ fBlueReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else {
+ std::cerr << "incorrect screencolor metadata : " << fCurrentColor << std::endl;
+ }
+ }
+ fCurrentColor = "";
+
+ fMetaData.push_back(fCurrentMetadata);
+ fCurrentMetadata.clear();
+ }
+
+ int getZoneIndex(std::vector<ZoneControl*>* table, int p, int val)
+ {
+ FAUSTFLOAT* zone = fZone[p];
+ for (size_t i = 0; i < table[val].size(); i++) {
+ if (zone == table[val][i]->getZone()) return int(i);
+ }
+ return -1;
+ }
+
+ void setConverter(std::vector<ZoneControl*>* table, int p, int val, int curve, double amin, double amid, double amax)
+ {
+ int id1 = getZoneIndex(table, p, 0);
+ int id2 = getZoneIndex(table, p, 1);
+ int id3 = getZoneIndex(table, p, 2);
+
+ // Deactivates everywhere..
+ if (id1 != -1) table[0][id1]->setActive(false);
+ if (id2 != -1) table[1][id2]->setActive(false);
+ if (id3 != -1) table[2][id3]->setActive(false);
+
+ if (val == -1) { // Means: no more mapping...
+ // So stay all deactivated...
+ } else {
+ int id4 = getZoneIndex(table, p, val);
+ if (id4 != -1) {
+ // Reactivate the one we edit...
+ table[val][id4]->setMappingValues(curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]);
+ table[val][id4]->setActive(true);
+ } else {
+ // Allocate a new CurveZoneControl which is 'active' by default
+ FAUSTFLOAT* zone = fZone[p];
+ table[val].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]));
+ }
+ }
+ }
+
+ void getConverter(std::vector<ZoneControl*>* table, int p, int& val, int& curve, double& amin, double& amid, double& amax)
+ {
+ int id1 = getZoneIndex(table, p, 0);
+ int id2 = getZoneIndex(table, p, 1);
+ int id3 = getZoneIndex(table, p, 2);
+
+ if (id1 != -1) {
+ val = 0;
+ curve = table[val][id1]->getCurve();
+ table[val][id1]->getMappingValues(amin, amid, amax);
+ } else if (id2 != -1) {
+ val = 1;
+ curve = table[val][id2]->getCurve();
+ table[val][id2]->getMappingValues(amin, amid, amax);
+ } else if (id3 != -1) {
+ val = 2;
+ curve = table[val][id3]->getCurve();
+ table[val][id3]->getMappingValues(amin, amid, amax);
+ } else {
+ val = -1; // No mapping
+ curve = 0;
+ amin = -100.;
+ amid = 0.;
+ amax = 100.;
+ }
+ }
+
+ public:
+
+ enum Type { kAcc = 0, kGyr = 1, kNoType };
+
+ APIUI() : fNumParameters(0), fHasScreenControl(false), fRedReader(0), fGreenReader(0), fBlueReader(0), fCurrentScale(kLin)
+ {}
+
+ virtual ~APIUI()
+ {
+ for (auto& it : fConversion) delete it;
+ for (int i = 0; i < 3; i++) {
+ for (auto& it : fAcc[i]) delete it;
+ for (auto& it : fGyr[i]) delete it;
+ }
+ delete fRedReader;
+ delete fGreenReader;
+ delete fBlueReader;
+ }
+
+ // -- widget's layouts
+
+ virtual void openTabBox(const char* label) { pushLabel(label); }
+ virtual void openHorizontalBox(const char* label) { pushLabel(label); }
+ virtual void openVerticalBox(const char* label) { pushLabel(label); }
+ virtual void closeBox() { popLabel(); }
+
+ // -- active widgets
+
+ virtual void addButton(const char* label, FAUSTFLOAT* zone)
+ {
+ addParameter(label, zone, 0, 0, 1, 1, kButton);
+ }
+
+ virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
+ {
+ addParameter(label, zone, 0, 0, 1, 1, kCheckButton);
+ }
+
+ virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+ {
+ addParameter(label, zone, init, min, max, step, kVSlider);
+ }
+
+ virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+ {
+ addParameter(label, zone, init, min, max, step, kHSlider);
+ }
+
+ virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+ {
+ addParameter(label, zone, init, min, max, step, kNumEntry);
+ }
+
+ // -- passive widgets
+
+ virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
+ {
+ addParameter(label, zone, min, min, max, (max-min)/1000.0, kHBargraph);
+ }
+
+ virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
+ {
+ addParameter(label, zone, min, min, max, (max-min)/1000.0, kVBargraph);
+ }
+
+ // -- soundfiles
+
+ virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) {}
+
+ // -- metadata declarations
+
+ virtual void declare(FAUSTFLOAT* zone, const char* key, const char* val)
+ {
+ // Keep metadata
+ fCurrentMetadata[key] = val;
+
+ if (strcmp(key, "scale") == 0) {
+ if (strcmp(val, "log") == 0) {
+ fCurrentScale = kLog;
+ } else if (strcmp(val, "exp") == 0) {
+ fCurrentScale = kExp;
+ } else {
+ fCurrentScale = kLin;
+ }
+ } else if (strcmp(key, "unit") == 0) {
+ fCurrentUnit = val;
+ } else if (strcmp(key, "acc") == 0) {
+ fCurrentAcc = val;
+ } else if (strcmp(key, "gyr") == 0) {
+ fCurrentGyr = val;
+ } else if (strcmp(key, "screencolor") == 0) {
+ fCurrentColor = val; // val = "red", "green", "blue" or "white"
+ } else if (strcmp(key, "tooltip") == 0) {
+ fCurrentTooltip = val;
+ }
+ }
+
+ virtual void declare(const char* key, const char* val)
+ {}
+
+ //-------------------------------------------------------------------------------
+ // Simple API part
+ //-------------------------------------------------------------------------------
+ int getParamsCount() { return fNumParameters; }
+ int getParamIndex(const char* path)
+ {
+ if (fPathMap.find(path) != fPathMap.end()) {
+ return fPathMap[path];
+ } else if (fLabelMap.find(path) != fLabelMap.end()) {
+ return fLabelMap[path];
+ } else {
+ return -1;
+ }
+ }
+ const char* getParamAddress(int p) { return fPaths[p].c_str(); }
+ const char* getParamLabel(int p) { return fLabels[p].c_str(); }
+ std::map<const char*, const char*> getMetadata(int p)
+ {
+ std::map<const char*, const char*> res;
+ std::map<std::string, std::string> metadata = fMetaData[p];
+ for (auto it : metadata) {
+ res[it.first.c_str()] = it.second.c_str();
+ }
+ return res;
+ }
+
+ const char* getMetadata(int p, const char* key)
+ {
+ return (fMetaData[p].find(key) != fMetaData[p].end()) ? fMetaData[p][key].c_str() : "";
+ }
+ FAUSTFLOAT getParamMin(int p) { return fMin[p]; }
+ FAUSTFLOAT getParamMax(int p) { return fMax[p]; }
+ FAUSTFLOAT getParamStep(int p) { return fStep[p]; }
+ FAUSTFLOAT getParamInit(int p) { return fInit[p]; }
+
+ FAUSTFLOAT* getParamZone(int p) { return fZone[p]; }
+ FAUSTFLOAT getParamValue(int p) { return *fZone[p]; }
+ void setParamValue(int p, FAUSTFLOAT v) { *fZone[p] = v; }
+
+ double getParamRatio(int p) { return fConversion[p]->faust2ui(*fZone[p]); }
+ void setParamRatio(int p, double r) { *fZone[p] = fConversion[p]->ui2faust(r); }
+
+ double value2ratio(int p, double r) { return fConversion[p]->faust2ui(r); }
+ double ratio2value(int p, double r) { return fConversion[p]->ui2faust(r); }
+
+ /**
+ * Return the control type (kAcc, kGyr, or -1) for a given parameter
+ *
+ * @param p - the UI parameter index
+ *
+ * @return the type
+ */
+ Type getParamType(int p)
+ {
+ if (p >= 0) {
+ if (getZoneIndex(fAcc, p, 0) != -1
+ || getZoneIndex(fAcc, p, 1) != -1
+ || getZoneIndex(fAcc, p, 2) != -1) {
+ return kAcc;
+ } else if (getZoneIndex(fGyr, p, 0) != -1
+ || getZoneIndex(fGyr, p, 1) != -1
+ || getZoneIndex(fGyr, p, 2) != -1) {
+ return kGyr;
+ }
+ }
+ return kNoType;
+ }
+
+ /**
+ * Return the Item type (kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry, kHBargraph, kVBargraph) for a given parameter
+ *
+ * @param p - the UI parameter index
+ *
+ * @return the Item type
+ */
+ ItemType getParamItemType(int p)
+ {
+ return fItemType[p];
+ }
+
+ /**
+ * Set a new value coming from an accelerometer, propagate it to all relevant FAUSTFLOAT* zones.
+ *
+ * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+ * @param value - the new value
+ *
+ */
+ void propagateAcc(int acc, double value)
+ {
+ for (size_t i = 0; i < fAcc[acc].size(); i++) {
+ fAcc[acc][i]->update(value);
+ }
+ }
+
+ /**
+ * Used to edit accelerometer curves and mapping. Set curve and related mapping for a given UI parameter.
+ *
+ * @param p - the UI parameter index
+ * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer (-1 means "no mapping")
+ * @param curve - between 0 and 3
+ * @param amin - mapping 'min' point
+ * @param amid - mapping 'middle' point
+ * @param amax - mapping 'max' point
+ *
+ */
+ void setAccConverter(int p, int acc, int curve, double amin, double amid, double amax)
+ {
+ setConverter(fAcc, p, acc, curve, amin, amid, amax);
+ }
+
+ /**
+ * Used to edit gyroscope curves and mapping. Set curve and related mapping for a given UI parameter.
+ *
+ * @param p - the UI parameter index
+ * @param acc - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope (-1 means "no mapping")
+ * @param curve - between 0 and 3
+ * @param amin - mapping 'min' point
+ * @param amid - mapping 'middle' point
+ * @param amax - mapping 'max' point
+ *
+ */
+ void setGyrConverter(int p, int gyr, int curve, double amin, double amid, double amax)
+ {
+ setConverter(fGyr, p, gyr, curve, amin, amid, amax);
+ }
+
+ /**
+ * Used to edit accelerometer curves and mapping. Get curve and related mapping for a given UI parameter.
+ *
+ * @param p - the UI parameter index
+ * @param acc - the acc value to be retrieved (-1 means "no mapping")
+ * @param curve - the curve value to be retrieved
+ * @param amin - the amin value to be retrieved
+ * @param amid - the amid value to be retrieved
+ * @param amax - the amax value to be retrieved
+ *
+ */
+ void getAccConverter(int p, int& acc, int& curve, double& amin, double& amid, double& amax)
+ {
+ getConverter(fAcc, p, acc, curve, amin, amid, amax);
+ }
+
+ /**
+ * Used to edit gyroscope curves and mapping. Get curve and related mapping for a given UI parameter.
+ *
+ * @param p - the UI parameter index
+ * @param gyr - the gyr value to be retrieved (-1 means "no mapping")
+ * @param curve - the curve value to be retrieved
+ * @param amin - the amin value to be retrieved
+ * @param amid - the amid value to be retrieved
+ * @param amax - the amax value to be retrieved
+ *
+ */
+ void getGyrConverter(int p, int& gyr, int& curve, double& amin, double& amid, double& amax)
+ {
+ getConverter(fGyr, p, gyr, curve, amin, amid, amax);
+ }
+
+ /**
+ * Set a new value coming from an gyroscope, propagate it to all relevant FAUSTFLOAT* zones.
+ *
+ * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
+ * @param value - the new value
+ *
+ */
+ void propagateGyr(int gyr, double value)
+ {
+ for (size_t i = 0; i < fGyr[gyr].size(); i++) {
+ fGyr[gyr][i]->update(value);
+ }
+ }
+
+ /**
+ * Get the number of FAUSTFLOAT* zones controlled with the accelerometer
+ *
+ * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+ * @return the number of zones
+ *
+ */
+ int getAccCount(int acc)
+ {
+ return (acc >= 0 && acc < 3) ? int(fAcc[acc].size()) : 0;
+ }
+
+ /**
+ * Get the number of FAUSTFLOAT* zones controlled with the gyroscope
+ *
+ * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
+ * @param the number of zones
+ *
+ */
+ int getGyrCount(int gyr)
+ {
+ return (gyr >= 0 && gyr < 3) ? int(fGyr[gyr].size()) : 0;
+ }
+
+ // getScreenColor() : -1 means no screen color control (no screencolor metadata found)
+ // otherwise return 0x00RRGGBB a ready to use color
+ int getScreenColor()
+ {
+ if (fHasScreenControl) {
+ int r = (fRedReader) ? fRedReader->getValue() : 0;
+ int g = (fGreenReader) ? fGreenReader->getValue() : 0;
+ int b = (fBlueReader) ? fBlueReader->getValue() : 0;
+ return (r<<16) | (g<<8) | b;
+ } else {
+ return -1;
+ }
+ }
+
+};
+
+#endif
+/************************** END APIUI.h **************************/
+
+// NOTE: "faust -scn name" changes the last line above to
+// #include <faust/name/name.h>
+
+//----------------------------------------------------------------------------
+// FAUST Generated Code
+//----------------------------------------------------------------------------
+
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+#include <algorithm>
+#include <cmath>
+#include <math.h>
+
+static float zitarevdsp_faustpower2_f(float value) {
+ return (value * value);
+}
+
+#ifndef FAUSTCLASS
+#define FAUSTCLASS zitarevdsp
+#endif
+
+#ifdef __APPLE__
+#define exp10f __exp10f
+#define exp10 __exp10
+#endif
+
+class zitarevdsp : public dsp {
+
+ private:
+
+ int IOTA;
+ float fVec0[16384];
+ float fVec1[16384];
+ FAUSTFLOAT fVslider0;
+ float fRec0[2];
+ FAUSTFLOAT fVslider1;
+ float fRec1[2];
+ int fSampleRate;
+ float fConst0;
+ float fConst1;
+ FAUSTFLOAT fVslider2;
+ FAUSTFLOAT fVslider3;
+ FAUSTFLOAT fVslider4;
+ FAUSTFLOAT fVslider5;
+ float fConst2;
+ float fConst3;
+ FAUSTFLOAT fVslider6;
+ FAUSTFLOAT fVslider7;
+ FAUSTFLOAT fVslider8;
+ float fConst4;
+ FAUSTFLOAT fVslider9;
+ float fRec15[2];
+ float fRec14[2];
+ float fVec2[32768];
+ float fConst5;
+ int iConst6;
+ float fConst7;
+ FAUSTFLOAT fVslider10;
+ float fVec3[2048];
+ int iConst8;
+ float fRec12[2];
+ float fConst9;
+ float fConst10;
+ float fRec19[2];
+ float fRec18[2];
+ float fVec4[32768];
+ float fConst11;
+ int iConst12;
+ float fVec5[4096];
+ int iConst13;
+ float fRec16[2];
+ float fConst14;
+ float fConst15;
+ float fRec23[2];
+ float fRec22[2];
+ float fVec6[16384];
+ float fConst16;
+ int iConst17;
+ float fVec7[4096];
+ int iConst18;
+ float fRec20[2];
+ float fConst19;
+ float fConst20;
+ float fRec27[2];
+ float fRec26[2];
+ float fVec8[32768];
+ float fConst21;
+ int iConst22;
+ float fVec9[4096];
+ int iConst23;
+ float fRec24[2];
+ float fConst24;
+ float fConst25;
+ float fRec31[2];
+ float fRec30[2];
+ float fVec10[16384];
+ float fConst26;
+ int iConst27;
+ float fVec11[2048];
+ int iConst28;
+ float fRec28[2];
+ float fConst29;
+ float fConst30;
+ float fRec35[2];
+ float fRec34[2];
+ float fVec12[16384];
+ float fConst31;
+ int iConst32;
+ float fVec13[4096];
+ int iConst33;
+ float fRec32[2];
+ float fConst34;
+ float fConst35;
+ float fRec39[2];
+ float fRec38[2];
+ float fVec14[16384];
+ float fConst36;
+ int iConst37;
+ float fVec15[4096];
+ int iConst38;
+ float fRec36[2];
+ float fConst39;
+ float fConst40;
+ float fRec43[2];
+ float fRec42[2];
+ float fVec16[16384];
+ float fConst41;
+ int iConst42;
+ float fVec17[2048];
+ int iConst43;
+ float fRec40[2];
+ float fRec4[3];
+ float fRec5[3];
+ float fRec6[3];
+ float fRec7[3];
+ float fRec8[3];
+ float fRec9[3];
+ float fRec10[3];
+ float fRec11[3];
+ float fRec3[3];
+ float fRec2[3];
+ float fRec45[3];
+ float fRec44[3];
+
+ public:
+
+ void metadata(Meta* m) {
+ m->declare("basics.lib/name", "Faust Basic Element Library");
+ m->declare("basics.lib/version", "0.1");
+ m->declare("delays.lib/name", "Faust Delay Library");
+ m->declare("delays.lib/version", "0.1");
+ m->declare("filename", "zitarevdsp.dsp");
+ m->declare("filters.lib/allpass_comb:author", "Julius O. Smith III");
+ m->declare("filters.lib/allpass_comb:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+ m->declare("filters.lib/allpass_comb:license", "MIT-style STK-4.3 license");
+ m->declare("filters.lib/fir:author", "Julius O. Smith III");
+ m->declare("filters.lib/fir:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+ m->declare("filters.lib/fir:license", "MIT-style STK-4.3 license");
+ m->declare("filters.lib/iir:author", "Julius O. Smith III");
+ m->declare("filters.lib/iir:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+ m->declare("filters.lib/iir:license", "MIT-style STK-4.3 license");
+ m->declare("filters.lib/lowpass0_highpass1", "MIT-style STK-4.3 license");
+ m->declare("filters.lib/lowpass0_highpass1:author", "Julius O. Smith III");
+ m->declare("filters.lib/lowpass:author", "Julius O. Smith III");
+ m->declare("filters.lib/lowpass:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+ m->declare("filters.lib/lowpass:license", "MIT-style STK-4.3 license");
+ m->declare("filters.lib/name", "Faust Filters Library");
+ m->declare("filters.lib/peak_eq_rm:author", "Julius O. Smith III");
+ m->declare("filters.lib/peak_eq_rm:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+ m->declare("filters.lib/peak_eq_rm:license", "MIT-style STK-4.3 license");
+ m->declare("filters.lib/tf1:author", "Julius O. Smith III");
+ m->declare("filters.lib/tf1:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+ m->declare("filters.lib/tf1:license", "MIT-style STK-4.3 license");
+ m->declare("filters.lib/tf1s:author", "Julius O. Smith III");
+ m->declare("filters.lib/tf1s:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+ m->declare("filters.lib/tf1s:license", "MIT-style STK-4.3 license");
+ m->declare("filters.lib/tf2:author", "Julius O. Smith III");
+ m->declare("filters.lib/tf2:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+ m->declare("filters.lib/tf2:license", "MIT-style STK-4.3 license");
+ m->declare("maths.lib/author", "GRAME");
+ m->declare("maths.lib/copyright", "GRAME");
+ m->declare("maths.lib/license", "LGPL with exception");
+ m->declare("maths.lib/name", "Faust Math Library");
+ m->declare("maths.lib/version", "2.3");
+ m->declare("name", "zitarevdsp");
+ m->declare("platform.lib/name", "Generic Platform Library");
+ m->declare("platform.lib/version", "0.1");
+ m->declare("reverbs.lib/name", "Faust Reverb Library");
+ m->declare("reverbs.lib/version", "0.0");
+ m->declare("routes.lib/name", "Faust Signal Routing Library");
+ m->declare("routes.lib/version", "0.2");
+ m->declare("signals.lib/name", "Faust Signal Routing Library");
+ m->declare("signals.lib/version", "0.0");
+ }
+
+ virtual int getNumInputs() {
+ return 2;
+ }
+ virtual int getNumOutputs() {
+ return 2;
+ }
+ virtual int getInputRate(int channel) {
+ int rate;
+ switch ((channel)) {
+ case 0: {
+ rate = 1;
+ break;
+ }
+ case 1: {
+ rate = 1;
+ break;
+ }
+ default: {
+ rate = -1;
+ break;
+ }
+ }
+ return rate;
+ }
+ virtual int getOutputRate(int channel) {
+ int rate;
+ switch ((channel)) {
+ case 0: {
+ rate = 1;
+ break;
+ }
+ case 1: {
+ rate = 1;
+ break;
+ }
+ default: {
+ rate = -1;
+ break;
+ }
+ }
+ return rate;
+ }
+
+ static void classInit(int sample_rate) {
+ }
+
+ virtual void instanceConstants(int sample_rate) {
+ fSampleRate = sample_rate;
+ fConst0 = std::min<float>(192000.0f, std::max<float>(1.0f, float(fSampleRate)));
+ fConst1 = (6.28318548f / fConst0);
+ fConst2 = std::floor(((0.219990999f * fConst0) + 0.5f));
+ fConst3 = ((0.0f - (6.90775537f * fConst2)) / fConst0);
+ fConst4 = (3.14159274f / fConst0);
+ fConst5 = std::floor(((0.0191229992f * fConst0) + 0.5f));
+ iConst6 = int(std::min<float>(16384.0f, std::max<float>(0.0f, (fConst2 - fConst5))));
+ fConst7 = (0.00100000005f * fConst0);
+ iConst8 = int(std::min<float>(1024.0f, std::max<float>(0.0f, (fConst5 + -1.0f))));
+ fConst9 = std::floor(((0.256891012f * fConst0) + 0.5f));
+ fConst10 = ((0.0f - (6.90775537f * fConst9)) / fConst0);
+ fConst11 = std::floor(((0.0273330007f * fConst0) + 0.5f));
+ iConst12 = int(std::min<float>(16384.0f, std::max<float>(0.0f, (fConst9 - fConst11))));
+ iConst13 = int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst11 + -1.0f))));
+ fConst14 = std::floor(((0.192303002f * fConst0) + 0.5f));
+ fConst15 = ((0.0f - (6.90775537f * fConst14)) / fConst0);
+ fConst16 = std::floor(((0.0292910002f * fConst0) + 0.5f));
+ iConst17 = int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst14 - fConst16))));
+ iConst18 = int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst16 + -1.0f))));
+ fConst19 = std::floor(((0.210389003f * fConst0) + 0.5f));
+ fConst20 = ((0.0f - (6.90775537f * fConst19)) / fConst0);
+ fConst21 = std::floor(((0.0244210009f * fConst0) + 0.5f));
+ iConst22 = int(std::min<float>(16384.0f, std::max<float>(0.0f, (fConst19 - fConst21))));
+ iConst23 = int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst21 + -1.0f))));
+ fConst24 = std::floor(((0.125f * fConst0) + 0.5f));
+ fConst25 = ((0.0f - (6.90775537f * fConst24)) / fConst0);
+ fConst26 = std::floor(((0.0134579996f * fConst0) + 0.5f));
+ iConst27 = int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst24 - fConst26))));
+ iConst28 = int(std::min<float>(1024.0f, std::max<float>(0.0f, (fConst26 + -1.0f))));
+ fConst29 = std::floor(((0.127837002f * fConst0) + 0.5f));
+ fConst30 = ((0.0f - (6.90775537f * fConst29)) / fConst0);
+ fConst31 = std::floor(((0.0316039994f * fConst0) + 0.5f));
+ iConst32 = int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst29 - fConst31))));
+ iConst33 = int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst31 + -1.0f))));
+ fConst34 = std::floor(((0.174713001f * fConst0) + 0.5f));
+ fConst35 = ((0.0f - (6.90775537f * fConst34)) / fConst0);
+ fConst36 = std::floor(((0.0229039993f * fConst0) + 0.5f));
+ iConst37 = int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst34 - fConst36))));
+ iConst38 = int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst36 + -1.0f))));
+ fConst39 = std::floor(((0.153128996f * fConst0) + 0.5f));
+ fConst40 = ((0.0f - (6.90775537f * fConst39)) / fConst0);
+ fConst41 = std::floor(((0.0203460008f * fConst0) + 0.5f));
+ iConst42 = int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst39 - fConst41))));
+ iConst43 = int(std::min<float>(1024.0f, std::max<float>(0.0f, (fConst41 + -1.0f))));
+ }
+
+ virtual void instanceResetUserInterface() {
+ fVslider0 = FAUSTFLOAT(-3.0f);
+ fVslider1 = FAUSTFLOAT(0.0f);
+ fVslider2 = FAUSTFLOAT(1500.0f);
+ fVslider3 = FAUSTFLOAT(0.0f);
+ fVslider4 = FAUSTFLOAT(315.0f);
+ fVslider5 = FAUSTFLOAT(0.0f);
+ fVslider6 = FAUSTFLOAT(2.0f);
+ fVslider7 = FAUSTFLOAT(6000.0f);
+ fVslider8 = FAUSTFLOAT(3.0f);
+ fVslider9 = FAUSTFLOAT(200.0f);
+ fVslider10 = FAUSTFLOAT(60.0f);
+ }
+
+ virtual void instanceClear() {
+ IOTA = 0;
+ for (int l0 = 0; (l0 < 16384); l0 = (l0 + 1)) {
+ fVec0[l0] = 0.0f;
+ }
+ for (int l1 = 0; (l1 < 16384); l1 = (l1 + 1)) {
+ fVec1[l1] = 0.0f;
+ }
+ for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) {
+ fRec0[l2] = 0.0f;
+ }
+ for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) {
+ fRec1[l3] = 0.0f;
+ }
+ for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) {
+ fRec15[l4] = 0.0f;
+ }
+ for (int l5 = 0; (l5 < 2); l5 = (l5 + 1)) {
+ fRec14[l5] = 0.0f;
+ }
+ for (int l6 = 0; (l6 < 32768); l6 = (l6 + 1)) {
+ fVec2[l6] = 0.0f;
+ }
+ for (int l7 = 0; (l7 < 2048); l7 = (l7 + 1)) {
+ fVec3[l7] = 0.0f;
+ }
+ for (int l8 = 0; (l8 < 2); l8 = (l8 + 1)) {
+ fRec12[l8] = 0.0f;
+ }
+ for (int l9 = 0; (l9 < 2); l9 = (l9 + 1)) {
+ fRec19[l9] = 0.0f;
+ }
+ for (int l10 = 0; (l10 < 2); l10 = (l10 + 1)) {
+ fRec18[l10] = 0.0f;
+ }
+ for (int l11 = 0; (l11 < 32768); l11 = (l11 + 1)) {
+ fVec4[l11] = 0.0f;
+ }
+ for (int l12 = 0; (l12 < 4096); l12 = (l12 + 1)) {
+ fVec5[l12] = 0.0f;
+ }
+ for (int l13 = 0; (l13 < 2); l13 = (l13 + 1)) {
+ fRec16[l13] = 0.0f;
+ }
+ for (int l14 = 0; (l14 < 2); l14 = (l14 + 1)) {
+ fRec23[l14] = 0.0f;
+ }
+ for (int l15 = 0; (l15 < 2); l15 = (l15 + 1)) {
+ fRec22[l15] = 0.0f;
+ }
+ for (int l16 = 0; (l16 < 16384); l16 = (l16 + 1)) {
+ fVec6[l16] = 0.0f;
+ }
+ for (int l17 = 0; (l17 < 4096); l17 = (l17 + 1)) {
+ fVec7[l17] = 0.0f;
+ }
+ for (int l18 = 0; (l18 < 2); l18 = (l18 + 1)) {
+ fRec20[l18] = 0.0f;
+ }
+ for (int l19 = 0; (l19 < 2); l19 = (l19 + 1)) {
+ fRec27[l19] = 0.0f;
+ }
+ for (int l20 = 0; (l20 < 2); l20 = (l20 + 1)) {
+ fRec26[l20] = 0.0f;
+ }
+ for (int l21 = 0; (l21 < 32768); l21 = (l21 + 1)) {
+ fVec8[l21] = 0.0f;
+ }
+ for (int l22 = 0; (l22 < 4096); l22 = (l22 + 1)) {
+ fVec9[l22] = 0.0f;
+ }
+ for (int l23 = 0; (l23 < 2); l23 = (l23 + 1)) {
+ fRec24[l23] = 0.0f;
+ }
+ for (int l24 = 0; (l24 < 2); l24 = (l24 + 1)) {
+ fRec31[l24] = 0.0f;
+ }
+ for (int l25 = 0; (l25 < 2); l25 = (l25 + 1)) {
+ fRec30[l25] = 0.0f;
+ }
+ for (int l26 = 0; (l26 < 16384); l26 = (l26 + 1)) {
+ fVec10[l26] = 0.0f;
+ }
+ for (int l27 = 0; (l27 < 2048); l27 = (l27 + 1)) {
+ fVec11[l27] = 0.0f;
+ }
+ for (int l28 = 0; (l28 < 2); l28 = (l28 + 1)) {
+ fRec28[l28] = 0.0f;
+ }
+ for (int l29 = 0; (l29 < 2); l29 = (l29 + 1)) {
+ fRec35[l29] = 0.0f;
+ }
+ for (int l30 = 0; (l30 < 2); l30 = (l30 + 1)) {
+ fRec34[l30] = 0.0f;
+ }
+ for (int l31 = 0; (l31 < 16384); l31 = (l31 + 1)) {
+ fVec12[l31] = 0.0f;
+ }
+ for (int l32 = 0; (l32 < 4096); l32 = (l32 + 1)) {
+ fVec13[l32] = 0.0f;
+ }
+ for (int l33 = 0; (l33 < 2); l33 = (l33 + 1)) {
+ fRec32[l33] = 0.0f;
+ }
+ for (int l34 = 0; (l34 < 2); l34 = (l34 + 1)) {
+ fRec39[l34] = 0.0f;
+ }
+ for (int l35 = 0; (l35 < 2); l35 = (l35 + 1)) {
+ fRec38[l35] = 0.0f;
+ }
+ for (int l36 = 0; (l36 < 16384); l36 = (l36 + 1)) {
+ fVec14[l36] = 0.0f;
+ }
+ for (int l37 = 0; (l37 < 4096); l37 = (l37 + 1)) {
+ fVec15[l37] = 0.0f;
+ }
+ for (int l38 = 0; (l38 < 2); l38 = (l38 + 1)) {
+ fRec36[l38] = 0.0f;
+ }
+ for (int l39 = 0; (l39 < 2); l39 = (l39 + 1)) {
+ fRec43[l39] = 0.0f;
+ }
+ for (int l40 = 0; (l40 < 2); l40 = (l40 + 1)) {
+ fRec42[l40] = 0.0f;
+ }
+ for (int l41 = 0; (l41 < 16384); l41 = (l41 + 1)) {
+ fVec16[l41] = 0.0f;
+ }
+ for (int l42 = 0; (l42 < 2048); l42 = (l42 + 1)) {
+ fVec17[l42] = 0.0f;
+ }
+ for (int l43 = 0; (l43 < 2); l43 = (l43 + 1)) {
+ fRec40[l43] = 0.0f;
+ }
+ for (int l44 = 0; (l44 < 3); l44 = (l44 + 1)) {
+ fRec4[l44] = 0.0f;
+ }
+ for (int l45 = 0; (l45 < 3); l45 = (l45 + 1)) {
+ fRec5[l45] = 0.0f;
+ }
+ for (int l46 = 0; (l46 < 3); l46 = (l46 + 1)) {
+ fRec6[l46] = 0.0f;
+ }
+ for (int l47 = 0; (l47 < 3); l47 = (l47 + 1)) {
+ fRec7[l47] = 0.0f;
+ }
+ for (int l48 = 0; (l48 < 3); l48 = (l48 + 1)) {
+ fRec8[l48] = 0.0f;
+ }
+ for (int l49 = 0; (l49 < 3); l49 = (l49 + 1)) {
+ fRec9[l49] = 0.0f;
+ }
+ for (int l50 = 0; (l50 < 3); l50 = (l50 + 1)) {
+ fRec10[l50] = 0.0f;
+ }
+ for (int l51 = 0; (l51 < 3); l51 = (l51 + 1)) {
+ fRec11[l51] = 0.0f;
+ }
+ for (int l52 = 0; (l52 < 3); l52 = (l52 + 1)) {
+ fRec3[l52] = 0.0f;
+ }
+ for (int l53 = 0; (l53 < 3); l53 = (l53 + 1)) {
+ fRec2[l53] = 0.0f;
+ }
+ for (int l54 = 0; (l54 < 3); l54 = (l54 + 1)) {
+ fRec45[l54] = 0.0f;
+ }
+ for (int l55 = 0; (l55 < 3); l55 = (l55 + 1)) {
+ fRec44[l55] = 0.0f;
+ }
+ }
+
+ virtual void init(int sample_rate) {
+ classInit(sample_rate);
+ instanceInit(sample_rate);
+ }
+ virtual void instanceInit(int sample_rate) {
+ instanceConstants(sample_rate);
+ instanceResetUserInterface();
+ instanceClear();
+ }
+
+ virtual zitarevdsp* clone() {
+ return new zitarevdsp();
+ }
+
+ virtual int getSampleRate() {
+ return fSampleRate;
+ }
+
+ virtual void buildUserInterface(UI* ui_interface) {
+ ui_interface->declare(0, "0", "");
+ ui_interface->declare(0, "tooltip", "~ ZITA REV1 FEEDBACK DELAY NETWORK (FDN) & SCHROEDER ALLPASS-COMB REVERBERATOR (8x8). See Faust's reverbs.lib for documentation and references");
+ ui_interface->openHorizontalBox("Zita_Rev1");
+ ui_interface->declare(0, "1", "");
+ ui_interface->openHorizontalBox("Input");
+ ui_interface->declare(&fVslider10, "1", "");
+ ui_interface->declare(&fVslider10, "style", "knob");
+ ui_interface->declare(&fVslider10, "tooltip", "Delay in ms before reverberation begins");
+ ui_interface->declare(&fVslider10, "unit", "ms");
+ ui_interface->addVerticalSlider("In Delay", &fVslider10, 60.0f, 20.0f, 100.0f, 1.0f);
+ ui_interface->closeBox();
+ ui_interface->declare(0, "2", "");
+ ui_interface->openHorizontalBox("Decay Times in Bands (see tooltips)");
+ ui_interface->declare(&fVslider9, "1", "");
+ ui_interface->declare(&fVslider9, "scale", "log");
+ ui_interface->declare(&fVslider9, "style", "knob");
+ ui_interface->declare(&fVslider9, "tooltip", "Crossover frequency (Hz) separating low and middle frequencies");
+ ui_interface->declare(&fVslider9, "unit", "Hz");
+ ui_interface->addVerticalSlider("LF X", &fVslider9, 200.0f, 50.0f, 1000.0f, 1.0f);
+ ui_interface->declare(&fVslider8, "2", "");
+ ui_interface->declare(&fVslider8, "scale", "log");
+ ui_interface->declare(&fVslider8, "style", "knob");
+ ui_interface->declare(&fVslider8, "tooltip", "T60 = time (in seconds) to decay 60dB in low-frequency band");
+ ui_interface->declare(&fVslider8, "unit", "s");
+ ui_interface->addVerticalSlider("Low RT60", &fVslider8, 3.0f, 1.0f, 8.0f, 0.100000001f);
+ ui_interface->declare(&fVslider6, "3", "");
+ ui_interface->declare(&fVslider6, "scale", "log");
+ ui_interface->declare(&fVslider6, "style", "knob");
+ ui_interface->declare(&fVslider6, "tooltip", "T60 = time (in seconds) to decay 60dB in middle band");
+ ui_interface->declare(&fVslider6, "unit", "s");
+ ui_interface->addVerticalSlider("Mid RT60", &fVslider6, 2.0f, 1.0f, 8.0f, 0.100000001f);
+ ui_interface->declare(&fVslider7, "4", "");
+ ui_interface->declare(&fVslider7, "scale", "log");
+ ui_interface->declare(&fVslider7, "style", "knob");
+ ui_interface->declare(&fVslider7, "tooltip", "Frequency (Hz) at which the high-frequency T60 is half the middle-band's T60");
+ ui_interface->declare(&fVslider7, "unit", "Hz");
+ ui_interface->addVerticalSlider("HF Damping", &fVslider7, 6000.0f, 1500.0f, 23520.0f, 1.0f);
+ ui_interface->closeBox();
+ ui_interface->declare(0, "3", "");
+ ui_interface->openHorizontalBox("RM Peaking Equalizer 1");
+ ui_interface->declare(&fVslider4, "1", "");
+ ui_interface->declare(&fVslider4, "scale", "log");
+ ui_interface->declare(&fVslider4, "style", "knob");
+ ui_interface->declare(&fVslider4, "tooltip", "Center-frequency of second-order Regalia-Mitra peaking equalizer section 1");
+ ui_interface->declare(&fVslider4, "unit", "Hz");
+ ui_interface->addVerticalSlider("Eq1 Freq", &fVslider4, 315.0f, 40.0f, 2500.0f, 1.0f);
+ ui_interface->declare(&fVslider5, "2", "");
+ ui_interface->declare(&fVslider5, "style", "knob");
+ ui_interface->declare(&fVslider5, "tooltip", "Peak level in dB of second-order Regalia-Mitra peaking equalizer section 1");
+ ui_interface->declare(&fVslider5, "unit", "dB");
+ ui_interface->addVerticalSlider("Eq1 Level", &fVslider5, 0.0f, -15.0f, 15.0f, 0.100000001f);
+ ui_interface->closeBox();
+ ui_interface->declare(0, "4", "");
+ ui_interface->openHorizontalBox("RM Peaking Equalizer 2");
+ ui_interface->declare(&fVslider2, "1", "");
+ ui_interface->declare(&fVslider2, "scale", "log");
+ ui_interface->declare(&fVslider2, "style", "knob");
+ ui_interface->declare(&fVslider2, "tooltip", "Center-frequency of second-order Regalia-Mitra peaking equalizer section 2");
+ ui_interface->declare(&fVslider2, "unit", "Hz");
+ ui_interface->addVerticalSlider("Eq2 Freq", &fVslider2, 1500.0f, 160.0f, 10000.0f, 1.0f);
+ ui_interface->declare(&fVslider3, "2", "");
+ ui_interface->declare(&fVslider3, "style", "knob");
+ ui_interface->declare(&fVslider3, "tooltip", "Peak level in dB of second-order Regalia-Mitra peaking equalizer section 2");
+ ui_interface->declare(&fVslider3, "unit", "dB");
+ ui_interface->addVerticalSlider("Eq2 Level", &fVslider3, 0.0f, -15.0f, 15.0f, 0.100000001f);
+ ui_interface->closeBox();
+ ui_interface->declare(0, "5", "");
+ ui_interface->openHorizontalBox("Output");
+ ui_interface->declare(&fVslider1, "1", "");
+ ui_interface->declare(&fVslider1, "style", "knob");
+ ui_interface->declare(&fVslider1, "tooltip", "Dry/Wet Mix: 0 = dry, 1 = wet");
+ ui_interface->addVerticalSlider("Wet", &fVslider1, 0.0f, 0.0f, 1.0f, 0.00999999978f);
+ ui_interface->declare(&fVslider0, "2", "");
+ ui_interface->declare(&fVslider0, "style", "knob");
+ ui_interface->declare(&fVslider0, "tooltip", "Output scale factor");
+ ui_interface->declare(&fVslider0, "unit", "dB");
+ ui_interface->addVerticalSlider("Level", &fVslider0, -3.0f, -70.0f, 20.0f, 0.100000001f);
+ ui_interface->closeBox();
+ ui_interface->closeBox();
+ }
+
+ virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
+ FAUSTFLOAT* input0 = inputs[0];
+ FAUSTFLOAT* input1 = inputs[1];
+ FAUSTFLOAT* output0 = outputs[0];
+ FAUSTFLOAT* output1 = outputs[1];
+ float fSlow0 = (0.00100000005f * std::pow(10.0f, (0.0500000007f * float(fVslider0))));
+ float fSlow1 = (0.00100000005f * float(fVslider1));
+ float fSlow2 = float(fVslider2);
+ float fSlow3 = std::pow(10.0f, (0.0500000007f * float(fVslider3)));
+ float fSlow4 = (fConst1 * (fSlow2 / std::sqrt(std::max<float>(0.0f, fSlow3))));
+ float fSlow5 = ((1.0f - fSlow4) / (fSlow4 + 1.0f));
+ float fSlow6 = float(fVslider4);
+ float fSlow7 = std::pow(10.0f, (0.0500000007f * float(fVslider5)));
+ float fSlow8 = (fConst1 * (fSlow6 / std::sqrt(std::max<float>(0.0f, fSlow7))));
+ float fSlow9 = ((1.0f - fSlow8) / (fSlow8 + 1.0f));
+ float fSlow10 = float(fVslider6);
+ float fSlow11 = std::exp((fConst3 / fSlow10));
+ float fSlow12 = zitarevdsp_faustpower2_f(fSlow11);
+ float fSlow13 = std::cos((fConst1 * float(fVslider7)));
+ float fSlow14 = (1.0f - (fSlow12 * fSlow13));
+ float fSlow15 = (1.0f - fSlow12);
+ float fSlow16 = (fSlow14 / fSlow15);
+ float fSlow17 = std::sqrt(std::max<float>(0.0f, ((zitarevdsp_faustpower2_f(fSlow14) / zitarevdsp_faustpower2_f(fSlow15)) + -1.0f)));
+ float fSlow18 = (fSlow16 - fSlow17);
+ float fSlow19 = (fSlow11 * (fSlow17 + (1.0f - fSlow16)));
+ float fSlow20 = float(fVslider8);
+ float fSlow21 = ((std::exp((fConst3 / fSlow20)) / fSlow11) + -1.0f);
+ float fSlow22 = (1.0f / std::tan((fConst4 * float(fVslider9))));
+ float fSlow23 = (1.0f / (fSlow22 + 1.0f));
+ float fSlow24 = (1.0f - fSlow22);
+ int iSlow25 = int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst7 * float(fVslider10)))));
+ float fSlow26 = std::exp((fConst10 / fSlow10));
+ float fSlow27 = zitarevdsp_faustpower2_f(fSlow26);
+ float fSlow28 = (1.0f - (fSlow27 * fSlow13));
+ float fSlow29 = (1.0f - fSlow27);
+ float fSlow30 = (fSlow28 / fSlow29);
+ float fSlow31 = std::sqrt(std::max<float>(0.0f, ((zitarevdsp_faustpower2_f(fSlow28) / zitarevdsp_faustpower2_f(fSlow29)) + -1.0f)));
+ float fSlow32 = (fSlow30 - fSlow31);
+ float fSlow33 = (fSlow26 * (fSlow31 + (1.0f - fSlow30)));
+ float fSlow34 = ((std::exp((fConst10 / fSlow20)) / fSlow26) + -1.0f);
+ float fSlow35 = std::exp((fConst15 / fSlow10));
+ float fSlow36 = zitarevdsp_faustpower2_f(fSlow35);
+ float fSlow37 = (1.0f - (fSlow36 * fSlow13));
+ float fSlow38 = (1.0f - fSlow36);
+ float fSlow39 = (fSlow37 / fSlow38);
+ float fSlow40 = std::sqrt(std::max<float>(0.0f, ((zitarevdsp_faustpower2_f(fSlow37) / zitarevdsp_faustpower2_f(fSlow38)) + -1.0f)));
+ float fSlow41 = (fSlow39 - fSlow40);
+ float fSlow42 = (fSlow35 * (fSlow40 + (1.0f - fSlow39)));
+ float fSlow43 = ((std::exp((fConst15 / fSlow20)) / fSlow35) + -1.0f);
+ float fSlow44 = std::exp((fConst20 / fSlow10));
+ float fSlow45 = zitarevdsp_faustpower2_f(fSlow44);
+ float fSlow46 = (1.0f - (fSlow45 * fSlow13));
+ float fSlow47 = (1.0f - fSlow45);
+ float fSlow48 = (fSlow46 / fSlow47);
+ float fSlow49 = std::sqrt(std::max<float>(0.0f, ((zitarevdsp_faustpower2_f(fSlow46) / zitarevdsp_faustpower2_f(fSlow47)) + -1.0f)));
+ float fSlow50 = (fSlow48 - fSlow49);
+ float fSlow51 = (fSlow44 * (fSlow49 + (1.0f - fSlow48)));
+ float fSlow52 = ((std::exp((fConst20 / fSlow20)) / fSlow44) + -1.0f);
+ float fSlow53 = std::exp((fConst25 / fSlow10));
+ float fSlow54 = zitarevdsp_faustpower2_f(fSlow53);
+ float fSlow55 = (1.0f - (fSlow54 * fSlow13));
+ float fSlow56 = (1.0f - fSlow54);
+ float fSlow57 = (fSlow55 / fSlow56);
+ float fSlow58 = std::sqrt(std::max<float>(0.0f, ((zitarevdsp_faustpower2_f(fSlow55) / zitarevdsp_faustpower2_f(fSlow56)) + -1.0f)));
+ float fSlow59 = (fSlow57 - fSlow58);
+ float fSlow60 = (fSlow53 * (fSlow58 + (1.0f - fSlow57)));
+ float fSlow61 = ((std::exp((fConst25 / fSlow20)) / fSlow53) + -1.0f);
+ float fSlow62 = std::exp((fConst30 / fSlow10));
+ float fSlow63 = zitarevdsp_faustpower2_f(fSlow62);
+ float fSlow64 = (1.0f - (fSlow63 * fSlow13));
+ float fSlow65 = (1.0f - fSlow63);
+ float fSlow66 = (fSlow64 / fSlow65);
+ float fSlow67 = std::sqrt(std::max<float>(0.0f, ((zitarevdsp_faustpower2_f(fSlow64) / zitarevdsp_faustpower2_f(fSlow65)) + -1.0f)));
+ float fSlow68 = (fSlow66 - fSlow67);
+ float fSlow69 = (fSlow62 * (fSlow67 + (1.0f - fSlow66)));
+ float fSlow70 = ((std::exp((fConst30 / fSlow20)) / fSlow62) + -1.0f);
+ float fSlow71 = std::exp((fConst35 / fSlow10));
+ float fSlow72 = zitarevdsp_faustpower2_f(fSlow71);
+ float fSlow73 = (1.0f - (fSlow72 * fSlow13));
+ float fSlow74 = (1.0f - fSlow72);
+ float fSlow75 = (fSlow73 / fSlow74);
+ float fSlow76 = std::sqrt(std::max<float>(0.0f, ((zitarevdsp_faustpower2_f(fSlow73) / zitarevdsp_faustpower2_f(fSlow74)) + -1.0f)));
+ float fSlow77 = (fSlow75 - fSlow76);
+ float fSlow78 = (fSlow71 * (fSlow76 + (1.0f - fSlow75)));
+ float fSlow79 = ((std::exp((fConst35 / fSlow20)) / fSlow71) + -1.0f);
+ float fSlow80 = std::exp((fConst40 / fSlow10));
+ float fSlow81 = zitarevdsp_faustpower2_f(fSlow80);
+ float fSlow82 = (1.0f - (fSlow81 * fSlow13));
+ float fSlow83 = (1.0f - fSlow81);
+ float fSlow84 = (fSlow82 / fSlow83);
+ float fSlow85 = std::sqrt(std::max<float>(0.0f, ((zitarevdsp_faustpower2_f(fSlow82) / zitarevdsp_faustpower2_f(fSlow83)) + -1.0f)));
+ float fSlow86 = (fSlow84 - fSlow85);
+ float fSlow87 = (fSlow80 * (fSlow85 + (1.0f - fSlow84)));
+ float fSlow88 = ((std::exp((fConst40 / fSlow20)) / fSlow80) + -1.0f);
+ float fSlow89 = (0.0f - (std::cos((fConst1 * fSlow6)) * (fSlow9 + 1.0f)));
+ float fSlow90 = (0.0f - (std::cos((fConst1 * fSlow2)) * (fSlow5 + 1.0f)));
+ for (int i = 0; (i < count); i = (i + 1)) {
+ float fTemp0 = float(input0[i]);
+ fVec0[(IOTA & 16383)] = fTemp0;
+ float fTemp1 = float(input1[i]);
+ fVec1[(IOTA & 16383)] = fTemp1;
+ fRec0[0] = (fSlow0 + (0.999000013f * fRec0[1]));
+ fRec1[0] = (fSlow1 + (0.999000013f * fRec1[1]));
+ fRec15[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec15[1]) - (fRec11[1] + fRec11[2]))));
+ fRec14[0] = ((fSlow18 * fRec14[1]) + (fSlow19 * (fRec11[1] + (fSlow21 * fRec15[0]))));
+ fVec2[(IOTA & 32767)] = ((0.353553385f * fRec14[0]) + 9.99999968e-21f);
+ float fTemp2 = (0.300000012f * fVec1[((IOTA - iSlow25) & 16383)]);
+ float fTemp3 = (((0.600000024f * fRec12[1]) + fVec2[((IOTA - iConst6) & 32767)]) - fTemp2);
+ fVec3[(IOTA & 2047)] = fTemp3;
+ fRec12[0] = fVec3[((IOTA - iConst8) & 2047)];
+ float fRec13 = (0.0f - (0.600000024f * fTemp3));
+ fRec19[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec19[1]) - (fRec7[1] + fRec7[2]))));
+ fRec18[0] = ((fSlow32 * fRec18[1]) + (fSlow33 * (fRec7[1] + (fSlow34 * fRec19[0]))));
+ fVec4[(IOTA & 32767)] = ((0.353553385f * fRec18[0]) + 9.99999968e-21f);
+ float fTemp4 = (((0.600000024f * fRec16[1]) + fVec4[((IOTA - iConst12) & 32767)]) - fTemp2);
+ fVec5[(IOTA & 4095)] = fTemp4;
+ fRec16[0] = fVec5[((IOTA - iConst13) & 4095)];
+ float fRec17 = (0.0f - (0.600000024f * fTemp4));
+ fRec23[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec23[1]) - (fRec9[1] + fRec9[2]))));
+ fRec22[0] = ((fSlow41 * fRec22[1]) + (fSlow42 * (fRec9[1] + (fSlow43 * fRec23[0]))));
+ fVec6[(IOTA & 16383)] = ((0.353553385f * fRec22[0]) + 9.99999968e-21f);
+ float fTemp5 = (fVec6[((IOTA - iConst17) & 16383)] + (fTemp2 + (0.600000024f * fRec20[1])));
+ fVec7[(IOTA & 4095)] = fTemp5;
+ fRec20[0] = fVec7[((IOTA - iConst18) & 4095)];
+ float fRec21 = (0.0f - (0.600000024f * fTemp5));
+ fRec27[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec27[1]) - (fRec5[1] + fRec5[2]))));
+ fRec26[0] = ((fSlow50 * fRec26[1]) + (fSlow51 * (fRec5[1] + (fSlow52 * fRec27[0]))));
+ fVec8[(IOTA & 32767)] = ((0.353553385f * fRec26[0]) + 9.99999968e-21f);
+ float fTemp6 = (fTemp2 + ((0.600000024f * fRec24[1]) + fVec8[((IOTA - iConst22) & 32767)]));
+ fVec9[(IOTA & 4095)] = fTemp6;
+ fRec24[0] = fVec9[((IOTA - iConst23) & 4095)];
+ float fRec25 = (0.0f - (0.600000024f * fTemp6));
+ fRec31[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec31[1]) - (fRec10[1] + fRec10[2]))));
+ fRec30[0] = ((fSlow59 * fRec30[1]) + (fSlow60 * (fRec10[1] + (fSlow61 * fRec31[0]))));
+ fVec10[(IOTA & 16383)] = ((0.353553385f * fRec30[0]) + 9.99999968e-21f);
+ float fTemp7 = (0.300000012f * fVec0[((IOTA - iSlow25) & 16383)]);
+ float fTemp8 = (fVec10[((IOTA - iConst27) & 16383)] - (fTemp7 + (0.600000024f * fRec28[1])));
+ fVec11[(IOTA & 2047)] = fTemp8;
+ fRec28[0] = fVec11[((IOTA - iConst28) & 2047)];
+ float fRec29 = (0.600000024f * fTemp8);
+ fRec35[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec35[1]) - (fRec6[1] + fRec6[2]))));
+ fRec34[0] = ((fSlow68 * fRec34[1]) + (fSlow69 * (fRec6[1] + (fSlow70 * fRec35[0]))));
+ fVec12[(IOTA & 16383)] = ((0.353553385f * fRec34[0]) + 9.99999968e-21f);
+ float fTemp9 = (fVec12[((IOTA - iConst32) & 16383)] - (fTemp7 + (0.600000024f * fRec32[1])));
+ fVec13[(IOTA & 4095)] = fTemp9;
+ fRec32[0] = fVec13[((IOTA - iConst33) & 4095)];
+ float fRec33 = (0.600000024f * fTemp9);
+ fRec39[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec39[1]) - (fRec8[1] + fRec8[2]))));
+ fRec38[0] = ((fSlow77 * fRec38[1]) + (fSlow78 * (fRec8[1] + (fSlow79 * fRec39[0]))));
+ fVec14[(IOTA & 16383)] = ((0.353553385f * fRec38[0]) + 9.99999968e-21f);
+ float fTemp10 = ((fTemp7 + fVec14[((IOTA - iConst37) & 16383)]) - (0.600000024f * fRec36[1]));
+ fVec15[(IOTA & 4095)] = fTemp10;
+ fRec36[0] = fVec15[((IOTA - iConst38) & 4095)];
+ float fRec37 = (0.600000024f * fTemp10);
+ fRec43[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec43[1]) - (fRec4[1] + fRec4[2]))));
+ fRec42[0] = ((fSlow86 * fRec42[1]) + (fSlow87 * (fRec4[1] + (fSlow88 * fRec43[0]))));
+ fVec16[(IOTA & 16383)] = ((0.353553385f * fRec42[0]) + 9.99999968e-21f);
+ float fTemp11 = ((fVec16[((IOTA - iConst42) & 16383)] + fTemp7) - (0.600000024f * fRec40[1]));
+ fVec17[(IOTA & 2047)] = fTemp11;
+ fRec40[0] = fVec17[((IOTA - iConst43) & 2047)];
+ float fRec41 = (0.600000024f * fTemp11);
+ float fTemp12 = (fRec41 + fRec37);
+ float fTemp13 = (fRec29 + (fRec33 + fTemp12));
+ fRec4[0] = (fRec12[1] + (fRec16[1] + (fRec20[1] + (fRec24[1] + (fRec28[1] + (fRec32[1] + (fRec36[1] + (fRec40[1] + (fRec13 + (fRec17 + (fRec21 + (fRec25 + fTemp13))))))))))));
+ fRec5[0] = ((fRec28[1] + (fRec32[1] + (fRec36[1] + (fRec40[1] + fTemp13)))) - (fRec12[1] + (fRec16[1] + (fRec20[1] + (fRec24[1] + (fRec13 + (fRec17 + (fRec25 + fRec21))))))));
+ float fTemp14 = (fRec33 + fRec29);
+ fRec6[0] = ((fRec20[1] + (fRec24[1] + (fRec36[1] + (fRec40[1] + (fRec21 + (fRec25 + fTemp12)))))) - (fRec12[1] + (fRec16[1] + (fRec28[1] + (fRec32[1] + (fRec13 + (fRec17 + fTemp14)))))));
+ fRec7[0] = ((fRec12[1] + (fRec16[1] + (fRec36[1] + (fRec40[1] + (fRec13 + (fRec17 + fTemp12)))))) - (fRec20[1] + (fRec24[1] + (fRec28[1] + (fRec32[1] + (fRec21 + (fRec25 + fTemp14)))))));
+ float fTemp15 = (fRec41 + fRec33);
+ float fTemp16 = (fRec37 + fRec29);
+ fRec8[0] = ((fRec16[1] + (fRec24[1] + (fRec32[1] + (fRec40[1] + (fRec17 + (fRec25 + fTemp15)))))) - (fRec12[1] + (fRec20[1] + (fRec28[1] + (fRec36[1] + (fRec13 + (fRec21 + fTemp16)))))));
+ fRec9[0] = ((fRec12[1] + (fRec20[1] + (fRec32[1] + (fRec40[1] + (fRec13 + (fRec21 + fTemp15)))))) - (fRec16[1] + (fRec24[1] + (fRec28[1] + (fRec36[1] + (fRec17 + (fRec25 + fTemp16)))))));
+ float fTemp17 = (fRec41 + fRec29);
+ float fTemp18 = (fRec37 + fRec33);
+ fRec10[0] = ((fRec12[1] + (fRec24[1] + (fRec28[1] + (fRec40[1] + (fRec13 + (fRec25 + fTemp17)))))) - (fRec16[1] + (fRec20[1] + (fRec32[1] + (fRec36[1] + (fRec17 + (fRec21 + fTemp18)))))));
+ fRec11[0] = ((fRec16[1] + (fRec20[1] + (fRec28[1] + (fRec40[1] + (fRec17 + (fRec21 + fTemp17)))))) - (fRec12[1] + (fRec24[1] + (fRec32[1] + (fRec36[1] + (fRec13 + (fRec25 + fTemp18)))))));
+ float fTemp19 = (0.370000005f * (fRec5[0] + fRec6[0]));
+ float fTemp20 = (fSlow89 * fRec3[1]);
+ fRec3[0] = (fTemp19 - (fTemp20 + (fSlow9 * fRec3[2])));
+ float fTemp21 = (fSlow9 * fRec3[0]);
+ float fTemp22 = (0.5f * ((fTemp21 + (fRec3[2] + (fTemp19 + fTemp20))) + (fSlow7 * ((fTemp21 + (fTemp20 + fRec3[2])) - fTemp19))));
+ float fTemp23 = (fSlow90 * fRec2[1]);
+ fRec2[0] = (fTemp22 - (fTemp23 + (fSlow5 * fRec2[2])));
+ float fTemp24 = (fSlow5 * fRec2[0]);
+ float fTemp25 = (1.0f - fRec1[0]);
+ output0[i] = FAUSTFLOAT((fRec0[0] * ((0.5f * (fRec1[0] * ((fTemp24 + (fRec2[2] + (fTemp22 + fTemp23))) + (fSlow3 * ((fTemp24 + (fTemp23 + fRec2[2])) - fTemp22))))) + (fTemp0 * fTemp25))));
+ float fTemp26 = (0.370000005f * (fRec5[0] - fRec6[0]));
+ float fTemp27 = (fSlow89 * fRec45[1]);
+ fRec45[0] = (fTemp26 - (fTemp27 + (fSlow9 * fRec45[2])));
+ float fTemp28 = (fSlow9 * fRec45[0]);
+ float fTemp29 = (0.5f * ((fTemp28 + (fRec45[2] + (fTemp26 + fTemp27))) + (fSlow7 * ((fTemp28 + (fTemp27 + fRec45[2])) - fTemp26))));
+ float fTemp30 = (fSlow90 * fRec44[1]);
+ fRec44[0] = (fTemp29 - (fTemp30 + (fSlow5 * fRec44[2])));
+ float fTemp31 = (fSlow5 * fRec44[0]);
+ output1[i] = FAUSTFLOAT((fRec0[0] * ((0.5f * (fRec1[0] * ((fTemp31 + (fRec44[2] + (fTemp29 + fTemp30))) + (fSlow3 * ((fTemp31 + (fTemp30 + fRec44[2])) - fTemp29))))) + (fTemp1 * fTemp25))));
+ IOTA = (IOTA + 1);
+ fRec0[1] = fRec0[0];
+ fRec1[1] = fRec1[0];
+ fRec15[1] = fRec15[0];
+ fRec14[1] = fRec14[0];
+ fRec12[1] = fRec12[0];
+ fRec19[1] = fRec19[0];
+ fRec18[1] = fRec18[0];
+ fRec16[1] = fRec16[0];
+ fRec23[1] = fRec23[0];
+ fRec22[1] = fRec22[0];
+ fRec20[1] = fRec20[0];
+ fRec27[1] = fRec27[0];
+ fRec26[1] = fRec26[0];
+ fRec24[1] = fRec24[0];
+ fRec31[1] = fRec31[0];
+ fRec30[1] = fRec30[0];
+ fRec28[1] = fRec28[0];
+ fRec35[1] = fRec35[0];
+ fRec34[1] = fRec34[0];
+ fRec32[1] = fRec32[0];
+ fRec39[1] = fRec39[0];
+ fRec38[1] = fRec38[0];
+ fRec36[1] = fRec36[0];
+ fRec43[1] = fRec43[0];
+ fRec42[1] = fRec42[0];
+ fRec40[1] = fRec40[0];
+ fRec4[2] = fRec4[1];
+ fRec4[1] = fRec4[0];
+ fRec5[2] = fRec5[1];
+ fRec5[1] = fRec5[0];
+ fRec6[2] = fRec6[1];
+ fRec6[1] = fRec6[0];
+ fRec7[2] = fRec7[1];
+ fRec7[1] = fRec7[0];
+ fRec8[2] = fRec8[1];
+ fRec8[1] = fRec8[0];
+ fRec9[2] = fRec9[1];
+ fRec9[1] = fRec9[0];
+ fRec10[2] = fRec10[1];
+ fRec10[1] = fRec10[0];
+ fRec11[2] = fRec11[1];
+ fRec11[1] = fRec11[0];
+ fRec3[2] = fRec3[1];
+ fRec3[1] = fRec3[0];
+ fRec2[2] = fRec2[1];
+ fRec2[1] = fRec2[0];
+ fRec45[2] = fRec45[1];
+ fRec45[1] = fRec45[0];
+ fRec44[2] = fRec44[1];
+ fRec44[1] = fRec44[0];
+ }
+ }
+
+};
+
+#endif
diff --git a/src/zitarevmonodsp.h b/src/zitarevmonodsp.h
new file mode 100644
index 0000000..190453a
--- /dev/null
+++ b/src/zitarevmonodsp.h
@@ -0,0 +1,2357 @@
+/* ------------------------------------------------------------
+name: "zitarevmonodsp"
+Code generated with Faust 2.28.6 (https://faust.grame.fr)
+Compilation options: -lang cpp -inpl -scal -ftz 0
+------------------------------------------------------------ */
+
+#ifndef __zitarevmonodsp_H__
+#define __zitarevmonodsp_H__
+
+// NOTE: ANY INCLUDE-GUARD HERE MUST BE DERIVED FROM THE CLASS NAME
+//
+// faust2header.cpp - FAUST Architecture File
+// This is a simple variation of matlabplot.cpp in the Faust distribution
+// aimed at creating a simple C++ header file (.h) containing a Faust DSP.
+// See the Makefile for how to use it.
+
+/************************** BEGIN dsp.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __dsp__
+#define __dsp__
+
+#include <string>
+#include <vector>
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+struct UI;
+struct Meta;
+
+/**
+ * DSP memory manager.
+ */
+
+struct dsp_memory_manager {
+
+ virtual ~dsp_memory_manager() {}
+
+ virtual void* allocate(size_t size) = 0;
+ virtual void destroy(void* ptr) = 0;
+
+};
+
+/**
+* Signal processor definition.
+*/
+
+class dsp {
+
+ public:
+
+ dsp() {}
+ virtual ~dsp() {}
+
+ /* Return instance number of audio inputs */
+ virtual int getNumInputs() = 0;
+
+ /* Return instance number of audio outputs */
+ virtual int getNumOutputs() = 0;
+
+ /**
+ * Trigger the ui_interface parameter with instance specific calls
+ * to 'openTabBox', 'addButton', 'addVerticalSlider'... in order to build the UI.
+ *
+ * @param ui_interface - the user interface builder
+ */
+ virtual void buildUserInterface(UI* ui_interface) = 0;
+
+ /* Returns the sample rate currently used by the instance */
+ virtual int getSampleRate() = 0;
+
+ /**
+ * Global init, calls the following methods:
+ * - static class 'classInit': static tables initialization
+ * - 'instanceInit': constants and instance state initialization
+ *
+ * @param sample_rate - the sampling rate in Hertz
+ */
+ virtual void init(int sample_rate) = 0;
+
+ /**
+ * Init instance state
+ *
+ * @param sample_rate - the sampling rate in Hertz
+ */
+ virtual void instanceInit(int sample_rate) = 0;
+
+ /**
+ * Init instance constant state
+ *
+ * @param sample_rate - the sampling rate in Hertz
+ */
+ virtual void instanceConstants(int sample_rate) = 0;
+
+ /* Init default control parameters values */
+ virtual void instanceResetUserInterface() = 0;
+
+ /* Init instance state (delay lines...) */
+ virtual void instanceClear() = 0;
+
+ /**
+ * Return a clone of the instance.
+ *
+ * @return a copy of the instance on success, otherwise a null pointer.
+ */
+ virtual dsp* clone() = 0;
+
+ /**
+ * Trigger the Meta* parameter with instance specific calls to 'declare' (key, value) metadata.
+ *
+ * @param m - the Meta* meta user
+ */
+ virtual void metadata(Meta* m) = 0;
+
+ /**
+ * DSP instance computation, to be called with successive in/out audio buffers.
+ *
+ * @param count - the number of frames to compute
+ * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
+ * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (eiher float, double or quad)
+ *
+ */
+ virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) = 0;
+
+ /**
+ * DSP instance computation: alternative method to be used by subclasses.
+ *
+ * @param date_usec - the timestamp in microsec given by audio driver.
+ * @param count - the number of frames to compute
+ * @param inputs - the input audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
+ * @param outputs - the output audio buffers as an array of non-interleaved FAUSTFLOAT samples (either float, double or quad)
+ *
+ */
+ virtual void compute(double /*date_usec*/, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { compute(count, inputs, outputs); }
+
+};
+
+/**
+ * Generic DSP decorator.
+ */
+
+class decorator_dsp : public dsp {
+
+ protected:
+
+ dsp* fDSP;
+
+ public:
+
+ decorator_dsp(dsp* dsp = nullptr):fDSP(dsp) {}
+ virtual ~decorator_dsp() { delete fDSP; }
+
+ virtual int getNumInputs() { return fDSP->getNumInputs(); }
+ virtual int getNumOutputs() { return fDSP->getNumOutputs(); }
+ virtual void buildUserInterface(UI* ui_interface) { fDSP->buildUserInterface(ui_interface); }
+ virtual int getSampleRate() { return fDSP->getSampleRate(); }
+ virtual void init(int sample_rate) { fDSP->init(sample_rate); }
+ virtual void instanceInit(int sample_rate) { fDSP->instanceInit(sample_rate); }
+ virtual void instanceConstants(int sample_rate) { fDSP->instanceConstants(sample_rate); }
+ virtual void instanceResetUserInterface() { fDSP->instanceResetUserInterface(); }
+ virtual void instanceClear() { fDSP->instanceClear(); }
+ virtual decorator_dsp* clone() { return new decorator_dsp(fDSP->clone()); }
+ virtual void metadata(Meta* m) { fDSP->metadata(m); }
+ // Beware: subclasses usually have to overload the two 'compute' methods
+ virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(count, inputs, outputs); }
+ virtual void compute(double date_usec, int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) { fDSP->compute(date_usec, count, inputs, outputs); }
+
+};
+
+/**
+ * DSP factory class.
+ */
+
+class dsp_factory {
+
+ protected:
+
+ // So that to force sub-classes to use deleteDSPFactory(dsp_factory* factory);
+ virtual ~dsp_factory() {}
+
+ public:
+
+ virtual std::string getName() = 0;
+ virtual std::string getSHAKey() = 0;
+ virtual std::string getDSPCode() = 0;
+ virtual std::string getCompileOptions() = 0;
+ virtual std::vector<std::string> getLibraryList() = 0;
+ virtual std::vector<std::string> getIncludePathnames() = 0;
+
+ virtual dsp* createDSPInstance() = 0;
+
+ virtual void setMemoryManager(dsp_memory_manager* manager) = 0;
+ virtual dsp_memory_manager* getMemoryManager() = 0;
+
+};
+
+/**
+ * On Intel set FZ (Flush to Zero) and DAZ (Denormals Are Zero)
+ * flags to avoid costly denormals.
+ */
+
+#ifdef __SSE__
+ #include <xmmintrin.h>
+ #ifdef __SSE2__
+ #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8040)
+ #else
+ #define AVOIDDENORMALS _mm_setcsr(_mm_getcsr() | 0x8000)
+ #endif
+#else
+ #define AVOIDDENORMALS
+#endif
+
+#endif
+/************************** END dsp.h **************************/
+
+/************************** BEGIN APIUI.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef API_UI_H
+#define API_UI_H
+
+#include <sstream>
+#include <string>
+#include <vector>
+#include <iostream>
+#include <map>
+
+/************************** BEGIN meta.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __meta__
+#define __meta__
+
+struct Meta
+{
+ virtual ~Meta() {};
+ virtual void declare(const char* key, const char* value) = 0;
+
+};
+
+#endif
+/************************** END meta.h **************************/
+/************************** BEGIN UI.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2020 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __UI_H__
+#define __UI_H__
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+/*******************************************************************************
+ * UI : Faust DSP User Interface
+ * User Interface as expected by the buildUserInterface() method of a DSP.
+ * This abstract class contains only the method that the Faust compiler can
+ * generate to describe a DSP user interface.
+ ******************************************************************************/
+
+struct Soundfile;
+
+template <typename REAL>
+struct UIReal
+{
+ UIReal() {}
+ virtual ~UIReal() {}
+
+ // -- widget's layouts
+
+ virtual void openTabBox(const char* label) = 0;
+ virtual void openHorizontalBox(const char* label) = 0;
+ virtual void openVerticalBox(const char* label) = 0;
+ virtual void closeBox() = 0;
+
+ // -- active widgets
+
+ virtual void addButton(const char* label, REAL* zone) = 0;
+ virtual void addCheckButton(const char* label, REAL* zone) = 0;
+ virtual void addVerticalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
+ virtual void addHorizontalSlider(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
+ virtual void addNumEntry(const char* label, REAL* zone, REAL init, REAL min, REAL max, REAL step) = 0;
+
+ // -- passive widgets
+
+ virtual void addHorizontalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
+ virtual void addVerticalBargraph(const char* label, REAL* zone, REAL min, REAL max) = 0;
+
+ // -- soundfiles
+
+ virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) = 0;
+
+ // -- metadata declarations
+
+ virtual void declare(REAL* zone, const char* key, const char* val) {}
+};
+
+struct UI : public UIReal<FAUSTFLOAT>
+{
+ UI() {}
+ virtual ~UI() {}
+};
+
+#endif
+/************************** END UI.h **************************/
+/************************** BEGIN PathBuilder.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef FAUST_PATHBUILDER_H
+#define FAUST_PATHBUILDER_H
+
+#include <vector>
+#include <string>
+#include <algorithm>
+
+/*******************************************************************************
+ * PathBuilder : Faust User Interface
+ * Helper class to build complete hierarchical path for UI items.
+ ******************************************************************************/
+
+class PathBuilder
+{
+
+ protected:
+
+ std::vector<std::string> fControlsLevel;
+
+ public:
+
+ PathBuilder() {}
+ virtual ~PathBuilder() {}
+
+ std::string buildPath(const std::string& label)
+ {
+ std::string res = "/";
+ for (size_t i = 0; i < fControlsLevel.size(); i++) {
+ res += fControlsLevel[i];
+ res += "/";
+ }
+ res += label;
+ std::replace(res.begin(), res.end(), ' ', '_');
+ return res;
+ }
+
+ std::string buildLabel(std::string label)
+ {
+ std::replace(label.begin(), label.end(), ' ', '_');
+ return label;
+ }
+
+ void pushLabel(const std::string& label) { fControlsLevel.push_back(label); }
+ void popLabel() { fControlsLevel.pop_back(); }
+
+};
+
+#endif // FAUST_PATHBUILDER_H
+/************************** END PathBuilder.h **************************/
+/************************** BEGIN ValueConverter.h **************************/
+/************************************************************************
+ FAUST Architecture File
+ Copyright (C) 2003-2017 GRAME, Centre National de Creation Musicale
+ ---------------------------------------------------------------------
+ This Architecture section is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; If not, see <http://www.gnu.org/licenses/>.
+
+ EXCEPTION : As a special exception, you may create a larger work
+ that contains this FAUST architecture section and distribute
+ that work under terms of your choice, so long as this FAUST
+ architecture section is not modified.
+ ************************************************************************/
+
+#ifndef __ValueConverter__
+#define __ValueConverter__
+
+/***************************************************************************************
+ ValueConverter.h
+ (GRAME, Copyright 2015-2019)
+
+Set of conversion objects used to map user interface values (for example a gui slider
+delivering values between 0 and 1) to faust values (for example a vslider between
+20 and 20000) using a log scale.
+
+-- Utilities
+
+Range(lo,hi) : clip a value x between lo and hi
+Interpolator(lo,hi,v1,v2) : Maps a value x between lo and hi to a value y between v1 and v2
+Interpolator3pt(lo,mi,hi,v1,vm,v2) : Map values between lo mid hi to values between v1 vm v2
+
+-- Value Converters
+
+ValueConverter::ui2faust(x)
+ValueConverter::faust2ui(x)
+
+-- ValueConverters used for sliders depending of the scale
+
+LinearValueConverter(umin, umax, fmin, fmax)
+LinearValueConverter2(lo, mi, hi, v1, vm, v2) using 2 segments
+LogValueConverter(umin, umax, fmin, fmax)
+ExpValueConverter(umin, umax, fmin, fmax)
+
+-- ValueConverters used for accelerometers based on 3 points
+
+AccUpConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 0
+AccDownConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 1
+AccUpDownConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 2
+AccDownUpConverter(amin, amid, amax, fmin, fmid, fmax) -- curve 3
+
+-- lists of ZoneControl are used to implement accelerometers metadata for each axes
+
+ZoneControl(zone, valueConverter) : a zone with an accelerometer data converter
+
+-- ZoneReader are used to implement screencolor metadata
+
+ZoneReader(zone, valueConverter) : a zone with a data converter
+
+****************************************************************************************/
+
+#include <float.h>
+#include <algorithm> // std::max
+#include <cmath>
+#include <vector>
+#include <assert.h>
+
+//--------------------------------------------------------------------------------------
+// Interpolator(lo,hi,v1,v2)
+// Maps a value x between lo and hi to a value y between v1 and v2
+// y = v1 + (x-lo)/(hi-lo)*(v2-v1)
+// y = v1 + (x-lo) * coef with coef = (v2-v1)/(hi-lo)
+// y = v1 + x*coef - lo*coef
+// y = v1 - lo*coef + x*coef
+// y = offset + x*coef with offset = v1 - lo*coef
+//--------------------------------------------------------------------------------------
+class Interpolator
+{
+ private:
+
+ //--------------------------------------------------------------------------------------
+ // Range(lo,hi) clip a value between lo and hi
+ //--------------------------------------------------------------------------------------
+ struct Range
+ {
+ double fLo;
+ double fHi;
+
+ Range(double x, double y) : fLo(std::min<double>(x,y)), fHi(std::max<double>(x,y)) {}
+ double operator()(double x) { return (x<fLo) ? fLo : (x>fHi) ? fHi : x; }
+ };
+
+
+ Range fRange;
+ double fCoef;
+ double fOffset;
+
+ public:
+
+ Interpolator(double lo, double hi, double v1, double v2) : fRange(lo,hi)
+ {
+ if (hi != lo) {
+ // regular case
+ fCoef = (v2-v1)/(hi-lo);
+ fOffset = v1 - lo*fCoef;
+ } else {
+ // degenerate case, avoids division by zero
+ fCoef = 0;
+ fOffset = (v1+v2)/2;
+ }
+ }
+ double operator()(double v)
+ {
+ double x = fRange(v);
+ return fOffset + x*fCoef;
+ }
+
+ void getLowHigh(double& amin, double& amax)
+ {
+ amin = fRange.fLo;
+ amax = fRange.fHi;
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Interpolator3pt(lo,mi,hi,v1,vm,v2)
+// Map values between lo mid hi to values between v1 vm v2
+//--------------------------------------------------------------------------------------
+class Interpolator3pt
+{
+
+ private:
+
+ Interpolator fSegment1;
+ Interpolator fSegment2;
+ double fMid;
+
+ public:
+
+ Interpolator3pt(double lo, double mi, double hi, double v1, double vm, double v2) :
+ fSegment1(lo, mi, v1, vm),
+ fSegment2(mi, hi, vm, v2),
+ fMid(mi) {}
+ double operator()(double x) { return (x < fMid) ? fSegment1(x) : fSegment2(x); }
+
+ void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fSegment1.getLowHigh(amin, amid);
+ fSegment2.getLowHigh(amid, amax);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Abstract ValueConverter class. Converts values between UI and Faust representations
+//--------------------------------------------------------------------------------------
+class ValueConverter
+{
+
+ public:
+
+ virtual ~ValueConverter() {}
+ virtual double ui2faust(double x) = 0;
+ virtual double faust2ui(double x) = 0;
+};
+
+//--------------------------------------------------------------------------------------
+// A converter than can be updated
+//--------------------------------------------------------------------------------------
+
+class UpdatableValueConverter : public ValueConverter {
+
+ protected:
+
+ bool fActive;
+
+ public:
+
+ UpdatableValueConverter():fActive(true)
+ {}
+ virtual ~UpdatableValueConverter()
+ {}
+
+ virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max) = 0;
+ virtual void getMappingValues(double& amin, double& amid, double& amax) = 0;
+
+ void setActive(bool on_off) { fActive = on_off; }
+ bool getActive() { return fActive; }
+
+};
+
+
+//--------------------------------------------------------------------------------------
+// Linear conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class LinearValueConverter : public ValueConverter
+{
+
+ private:
+
+ Interpolator fUI2F;
+ Interpolator fF2UI;
+
+ public:
+
+ LinearValueConverter(double umin, double umax, double fmin, double fmax) :
+ fUI2F(umin,umax,fmin,fmax), fF2UI(fmin,fmax,umin,umax)
+ {}
+
+ LinearValueConverter() : fUI2F(0.,0.,0.,0.), fF2UI(0.,0.,0.,0.)
+ {}
+ virtual double ui2faust(double x) { return fUI2F(x); }
+ virtual double faust2ui(double x) { return fF2UI(x); }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Two segments linear conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class LinearValueConverter2 : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fUI2F;
+ Interpolator3pt fF2UI;
+
+ public:
+
+ LinearValueConverter2(double amin, double amid, double amax, double min, double init, double max) :
+ fUI2F(amin, amid, amax, min, init, max), fF2UI(min, init, max, amin, amid, amax)
+ {}
+
+ LinearValueConverter2() : fUI2F(0.,0.,0.,0.,0.,0.), fF2UI(0.,0.,0.,0.,0.,0.)
+ {}
+
+ virtual double ui2faust(double x) { return fUI2F(x); }
+ virtual double faust2ui(double x) { return fF2UI(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double min, double init, double max)
+ {
+ fUI2F = Interpolator3pt(amin, amid, amax, min, init, max);
+ fF2UI = Interpolator3pt(min, init, max, amin, amid, amax);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fUI2F.getMappingValues(amin, amid, amax);
+ }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Logarithmic conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class LogValueConverter : public LinearValueConverter
+{
+
+ public:
+
+ LogValueConverter(double umin, double umax, double fmin, double fmax) :
+ LinearValueConverter(umin, umax, std::log(std::max<double>(DBL_MIN, fmin)), std::log(std::max<double>(DBL_MIN, fmax)))
+ {}
+
+ virtual double ui2faust(double x) { return std::exp(LinearValueConverter::ui2faust(x)); }
+ virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::log(std::max<double>(x, DBL_MIN))); }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Exponential conversion between ui and Faust values
+//--------------------------------------------------------------------------------------
+class ExpValueConverter : public LinearValueConverter
+{
+
+ public:
+
+ ExpValueConverter(double umin, double umax, double fmin, double fmax) :
+ LinearValueConverter(umin, umax, std::min<double>(DBL_MAX, std::exp(fmin)), std::min<double>(DBL_MAX, std::exp(fmax)))
+ {}
+
+ virtual double ui2faust(double x) { return std::log(LinearValueConverter::ui2faust(x)); }
+ virtual double faust2ui(double x) { return LinearValueConverter::faust2ui(std::min<double>(DBL_MAX, std::exp(x))); }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using an Up curve (curve 0)
+//--------------------------------------------------------------------------------------
+class AccUpConverter : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fA2F;
+ Interpolator3pt fF2A;
+
+ public:
+
+ AccUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
+ fA2F(amin,amid,amax,fmin,fmid,fmax),
+ fF2A(fmin,fmid,fmax,amin,amid,amax)
+ {}
+
+ virtual double ui2faust(double x) { return fA2F(x); }
+ virtual double faust2ui(double x) { return fF2A(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
+ {
+ //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+ fA2F = Interpolator3pt(amin, amid, amax, fmin, fmid, fmax);
+ fF2A = Interpolator3pt(fmin, fmid, fmax, amin, amid, amax);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fA2F.getMappingValues(amin, amid, amax);
+ }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using a Down curve (curve 1)
+//--------------------------------------------------------------------------------------
+class AccDownConverter : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fA2F;
+ Interpolator3pt fF2A;
+
+ public:
+
+ AccDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
+ fA2F(amin,amid,amax,fmax,fmid,fmin),
+ fF2A(fmin,fmid,fmax,amax,amid,amin)
+ {}
+
+ virtual double ui2faust(double x) { return fA2F(x); }
+ virtual double faust2ui(double x) { return fF2A(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
+ {
+ //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+ fA2F = Interpolator3pt(amin, amid, amax, fmax, fmid, fmin);
+ fF2A = Interpolator3pt(fmin, fmid, fmax, amax, amid, amin);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fA2F.getMappingValues(amin, amid, amax);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using an Up-Down curve (curve 2)
+//--------------------------------------------------------------------------------------
+class AccUpDownConverter : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fA2F;
+ Interpolator fF2A;
+
+ public:
+
+ AccUpDownConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
+ fA2F(amin,amid,amax,fmin,fmax,fmin),
+ fF2A(fmin,fmax,amin,amax) // Special, pseudo inverse of a non monotonic function
+ {}
+
+ virtual double ui2faust(double x) { return fA2F(x); }
+ virtual double faust2ui(double x) { return fF2A(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
+ {
+ //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccUpDownConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+ fA2F = Interpolator3pt(amin, amid, amax, fmin, fmax, fmin);
+ fF2A = Interpolator(fmin, fmax, amin, amax);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fA2F.getMappingValues(amin, amid, amax);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Convert accelerometer or gyroscope values to Faust values
+// Using a Down-Up curve (curve 3)
+//--------------------------------------------------------------------------------------
+class AccDownUpConverter : public UpdatableValueConverter
+{
+
+ private:
+
+ Interpolator3pt fA2F;
+ Interpolator fF2A;
+
+ public:
+
+ AccDownUpConverter(double amin, double amid, double amax, double fmin, double fmid, double fmax) :
+ fA2F(amin,amid,amax,fmax,fmin,fmax),
+ fF2A(fmin,fmax,amin,amax) // Special, pseudo inverse of a non monotonic function
+ {}
+
+ virtual double ui2faust(double x) { return fA2F(x); }
+ virtual double faust2ui(double x) { return fF2A(x); }
+
+ virtual void setMappingValues(double amin, double amid, double amax, double fmin, double fmid, double fmax)
+ {
+ //__android_log_print(ANDROID_LOG_ERROR, "Faust", "AccDownUpConverter update %f %f %f %f %f %f", amin,amid,amax,fmin,fmid,fmax);
+ fA2F = Interpolator3pt(amin, amid, amax, fmax, fmin, fmax);
+ fF2A = Interpolator(fmin, fmax, amin, amax);
+ }
+
+ virtual void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fA2F.getMappingValues(amin, amid, amax);
+ }
+};
+
+//--------------------------------------------------------------------------------------
+// Base class for ZoneControl
+//--------------------------------------------------------------------------------------
+class ZoneControl
+{
+
+ protected:
+
+ FAUSTFLOAT* fZone;
+
+ public:
+
+ ZoneControl(FAUSTFLOAT* zone) : fZone(zone) {}
+ virtual ~ZoneControl() {}
+
+ virtual void update(double v) const {}
+
+ virtual void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max) {}
+ virtual void getMappingValues(double& amin, double& amid, double& amax) {}
+
+ FAUSTFLOAT* getZone() { return fZone; }
+
+ virtual void setActive(bool on_off) {}
+ virtual bool getActive() { return false; }
+
+ virtual int getCurve() { return -1; }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Useful to implement accelerometers metadata as a list of ZoneControl for each axes
+//--------------------------------------------------------------------------------------
+class ConverterZoneControl : public ZoneControl
+{
+
+ protected:
+
+ ValueConverter* fValueConverter;
+
+ public:
+
+ ConverterZoneControl(FAUSTFLOAT* zone, ValueConverter* converter) : ZoneControl(zone), fValueConverter(converter) {}
+ virtual ~ConverterZoneControl() { delete fValueConverter; } // Assuming fValueConverter is not kept elsewhere...
+
+ virtual void update(double v) const { *fZone = fValueConverter->ui2faust(v); }
+
+ ValueConverter* getConverter() { return fValueConverter; }
+
+};
+
+//--------------------------------------------------------------------------------------
+// Association of a zone and a four value converter, each one for each possible curve.
+// Useful to implement accelerometers metadata as a list of ZoneControl for each axes
+//--------------------------------------------------------------------------------------
+class CurveZoneControl : public ZoneControl
+{
+
+ private:
+
+ std::vector<UpdatableValueConverter*> fValueConverters;
+ int fCurve;
+
+ public:
+
+ CurveZoneControl(FAUSTFLOAT* zone, int curve, double amin, double amid, double amax, double min, double init, double max) : ZoneControl(zone), fCurve(0)
+ {
+ assert(curve >= 0 && curve <= 3);
+ fValueConverters.push_back(new AccUpConverter(amin, amid, amax, min, init, max));
+ fValueConverters.push_back(new AccDownConverter(amin, amid, amax, min, init, max));
+ fValueConverters.push_back(new AccUpDownConverter(amin, amid, amax, min, init, max));
+ fValueConverters.push_back(new AccDownUpConverter(amin, amid, amax, min, init, max));
+ fCurve = curve;
+ }
+ virtual ~CurveZoneControl()
+ {
+ std::vector<UpdatableValueConverter*>::iterator it;
+ for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
+ delete(*it);
+ }
+ }
+ void update(double v) const { if (fValueConverters[fCurve]->getActive()) *fZone = fValueConverters[fCurve]->ui2faust(v); }
+
+ void setMappingValues(int curve, double amin, double amid, double amax, double min, double init, double max)
+ {
+ fValueConverters[curve]->setMappingValues(amin, amid, amax, min, init, max);
+ fCurve = curve;
+ }
+
+ void getMappingValues(double& amin, double& amid, double& amax)
+ {
+ fValueConverters[fCurve]->getMappingValues(amin, amid, amax);
+ }
+
+ void setActive(bool on_off)
+ {
+ std::vector<UpdatableValueConverter*>::iterator it;
+ for (it = fValueConverters.begin(); it != fValueConverters.end(); it++) {
+ (*it)->setActive(on_off);
+ }
+ }
+
+ int getCurve() { return fCurve; }
+};
+
+class ZoneReader
+{
+
+ private:
+
+ FAUSTFLOAT* fZone;
+ Interpolator fInterpolator;
+
+ public:
+
+ ZoneReader(FAUSTFLOAT* zone, double lo, double hi) : fZone(zone), fInterpolator(lo, hi, 0, 255) {}
+
+ virtual ~ZoneReader() {}
+
+ int getValue()
+ {
+ return (fZone != nullptr) ? int(fInterpolator(*fZone)) : 127;
+ }
+
+};
+
+#endif
+/************************** END ValueConverter.h **************************/
+
+class APIUI : public PathBuilder, public Meta, public UI
+{
+ public:
+
+ enum ItemType { kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry, kHBargraph, kVBargraph };
+
+ protected:
+
+ enum { kLin = 0, kLog = 1, kExp = 2 };
+
+ int fNumParameters;
+ std::vector<std::string> fPaths;
+ std::vector<std::string> fLabels;
+ std::map<std::string, int> fPathMap;
+ std::map<std::string, int> fLabelMap;
+ std::vector<ValueConverter*> fConversion;
+ std::vector<FAUSTFLOAT*> fZone;
+ std::vector<FAUSTFLOAT> fInit;
+ std::vector<FAUSTFLOAT> fMin;
+ std::vector<FAUSTFLOAT> fMax;
+ std::vector<FAUSTFLOAT> fStep;
+ std::vector<ItemType> fItemType;
+ std::vector<std::map<std::string, std::string> > fMetaData;
+ std::vector<ZoneControl*> fAcc[3];
+ std::vector<ZoneControl*> fGyr[3];
+
+ // Screen color control
+ // "...[screencolor:red]..." etc.
+ bool fHasScreenControl; // true if control screen color metadata
+ ZoneReader* fRedReader;
+ ZoneReader* fGreenReader;
+ ZoneReader* fBlueReader;
+
+ // Current values controlled by metadata
+ std::string fCurrentUnit;
+ int fCurrentScale;
+ std::string fCurrentAcc;
+ std::string fCurrentGyr;
+ std::string fCurrentColor;
+ std::string fCurrentTooltip;
+ std::map<std::string, std::string> fCurrentMetadata;
+
+ // Add a generic parameter
+ virtual void addParameter(const char* label,
+ FAUSTFLOAT* zone,
+ FAUSTFLOAT init,
+ FAUSTFLOAT min,
+ FAUSTFLOAT max,
+ FAUSTFLOAT step,
+ ItemType type)
+ {
+ std::string path = buildPath(label);
+ fPathMap[path] = fLabelMap[label] = fNumParameters++;
+ fPaths.push_back(path);
+ fLabels.push_back(label);
+ fZone.push_back(zone);
+ fInit.push_back(init);
+ fMin.push_back(min);
+ fMax.push_back(max);
+ fStep.push_back(step);
+ fItemType.push_back(type);
+
+ // handle scale metadata
+ switch (fCurrentScale) {
+ case kLin:
+ fConversion.push_back(new LinearValueConverter(0, 1, min, max));
+ break;
+ case kLog:
+ fConversion.push_back(new LogValueConverter(0, 1, min, max));
+ break;
+ case kExp: fConversion.push_back(new ExpValueConverter(0, 1, min, max));
+ break;
+ }
+ fCurrentScale = kLin;
+
+ if (fCurrentAcc.size() > 0 && fCurrentGyr.size() > 0) {
+ std::cerr << "warning : 'acc' and 'gyr' metadata used for the same " << label << " parameter !!\n";
+ }
+
+ // handle acc metadata "...[acc : <axe> <curve> <amin> <amid> <amax>]..."
+ if (fCurrentAcc.size() > 0) {
+ std::istringstream iss(fCurrentAcc);
+ int axe, curve;
+ double amin, amid, amax;
+ iss >> axe >> curve >> amin >> amid >> amax;
+
+ if ((0 <= axe) && (axe < 3) &&
+ (0 <= curve) && (curve < 4) &&
+ (amin < amax) && (amin <= amid) && (amid <= amax))
+ {
+ fAcc[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
+ } else {
+ std::cerr << "incorrect acc metadata : " << fCurrentAcc << std::endl;
+ }
+ fCurrentAcc = "";
+ }
+
+ // handle gyr metadata "...[gyr : <axe> <curve> <amin> <amid> <amax>]..."
+ if (fCurrentGyr.size() > 0) {
+ std::istringstream iss(fCurrentGyr);
+ int axe, curve;
+ double amin, amid, amax;
+ iss >> axe >> curve >> amin >> amid >> amax;
+
+ if ((0 <= axe) && (axe < 3) &&
+ (0 <= curve) && (curve < 4) &&
+ (amin < amax) && (amin <= amid) && (amid <= amax))
+ {
+ fGyr[axe].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, min, init, max));
+ } else {
+ std::cerr << "incorrect gyr metadata : " << fCurrentGyr << std::endl;
+ }
+ fCurrentGyr = "";
+ }
+
+ // handle screencolor metadata "...[screencolor:red|green|blue|white]..."
+ if (fCurrentColor.size() > 0) {
+ if ((fCurrentColor == "red") && (fRedReader == 0)) {
+ fRedReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else if ((fCurrentColor == "green") && (fGreenReader == 0)) {
+ fGreenReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else if ((fCurrentColor == "blue") && (fBlueReader == 0)) {
+ fBlueReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else if ((fCurrentColor == "white") && (fRedReader == 0) && (fGreenReader == 0) && (fBlueReader == 0)) {
+ fRedReader = new ZoneReader(zone, min, max);
+ fGreenReader = new ZoneReader(zone, min, max);
+ fBlueReader = new ZoneReader(zone, min, max);
+ fHasScreenControl = true;
+ } else {
+ std::cerr << "incorrect screencolor metadata : " << fCurrentColor << std::endl;
+ }
+ }
+ fCurrentColor = "";
+
+ fMetaData.push_back(fCurrentMetadata);
+ fCurrentMetadata.clear();
+ }
+
+ int getZoneIndex(std::vector<ZoneControl*>* table, int p, int val)
+ {
+ FAUSTFLOAT* zone = fZone[p];
+ for (size_t i = 0; i < table[val].size(); i++) {
+ if (zone == table[val][i]->getZone()) return int(i);
+ }
+ return -1;
+ }
+
+ void setConverter(std::vector<ZoneControl*>* table, int p, int val, int curve, double amin, double amid, double amax)
+ {
+ int id1 = getZoneIndex(table, p, 0);
+ int id2 = getZoneIndex(table, p, 1);
+ int id3 = getZoneIndex(table, p, 2);
+
+ // Deactivates everywhere..
+ if (id1 != -1) table[0][id1]->setActive(false);
+ if (id2 != -1) table[1][id2]->setActive(false);
+ if (id3 != -1) table[2][id3]->setActive(false);
+
+ if (val == -1) { // Means: no more mapping...
+ // So stay all deactivated...
+ } else {
+ int id4 = getZoneIndex(table, p, val);
+ if (id4 != -1) {
+ // Reactivate the one we edit...
+ table[val][id4]->setMappingValues(curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]);
+ table[val][id4]->setActive(true);
+ } else {
+ // Allocate a new CurveZoneControl which is 'active' by default
+ FAUSTFLOAT* zone = fZone[p];
+ table[val].push_back(new CurveZoneControl(zone, curve, amin, amid, amax, fMin[p], fInit[p], fMax[p]));
+ }
+ }
+ }
+
+ void getConverter(std::vector<ZoneControl*>* table, int p, int& val, int& curve, double& amin, double& amid, double& amax)
+ {
+ int id1 = getZoneIndex(table, p, 0);
+ int id2 = getZoneIndex(table, p, 1);
+ int id3 = getZoneIndex(table, p, 2);
+
+ if (id1 != -1) {
+ val = 0;
+ curve = table[val][id1]->getCurve();
+ table[val][id1]->getMappingValues(amin, amid, amax);
+ } else if (id2 != -1) {
+ val = 1;
+ curve = table[val][id2]->getCurve();
+ table[val][id2]->getMappingValues(amin, amid, amax);
+ } else if (id3 != -1) {
+ val = 2;
+ curve = table[val][id3]->getCurve();
+ table[val][id3]->getMappingValues(amin, amid, amax);
+ } else {
+ val = -1; // No mapping
+ curve = 0;
+ amin = -100.;
+ amid = 0.;
+ amax = 100.;
+ }
+ }
+
+ public:
+
+ enum Type { kAcc = 0, kGyr = 1, kNoType };
+
+ APIUI() : fNumParameters(0), fHasScreenControl(false), fRedReader(0), fGreenReader(0), fBlueReader(0), fCurrentScale(kLin)
+ {}
+
+ virtual ~APIUI()
+ {
+ for (auto& it : fConversion) delete it;
+ for (int i = 0; i < 3; i++) {
+ for (auto& it : fAcc[i]) delete it;
+ for (auto& it : fGyr[i]) delete it;
+ }
+ delete fRedReader;
+ delete fGreenReader;
+ delete fBlueReader;
+ }
+
+ // -- widget's layouts
+
+ virtual void openTabBox(const char* label) { pushLabel(label); }
+ virtual void openHorizontalBox(const char* label) { pushLabel(label); }
+ virtual void openVerticalBox(const char* label) { pushLabel(label); }
+ virtual void closeBox() { popLabel(); }
+
+ // -- active widgets
+
+ virtual void addButton(const char* label, FAUSTFLOAT* zone)
+ {
+ addParameter(label, zone, 0, 0, 1, 1, kButton);
+ }
+
+ virtual void addCheckButton(const char* label, FAUSTFLOAT* zone)
+ {
+ addParameter(label, zone, 0, 0, 1, 1, kCheckButton);
+ }
+
+ virtual void addVerticalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+ {
+ addParameter(label, zone, init, min, max, step, kVSlider);
+ }
+
+ virtual void addHorizontalSlider(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+ {
+ addParameter(label, zone, init, min, max, step, kHSlider);
+ }
+
+ virtual void addNumEntry(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT init, FAUSTFLOAT min, FAUSTFLOAT max, FAUSTFLOAT step)
+ {
+ addParameter(label, zone, init, min, max, step, kNumEntry);
+ }
+
+ // -- passive widgets
+
+ virtual void addHorizontalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
+ {
+ addParameter(label, zone, min, min, max, (max-min)/1000.0, kHBargraph);
+ }
+
+ virtual void addVerticalBargraph(const char* label, FAUSTFLOAT* zone, FAUSTFLOAT min, FAUSTFLOAT max)
+ {
+ addParameter(label, zone, min, min, max, (max-min)/1000.0, kVBargraph);
+ }
+
+ // -- soundfiles
+
+ virtual void addSoundfile(const char* label, const char* filename, Soundfile** sf_zone) {}
+
+ // -- metadata declarations
+
+ virtual void declare(FAUSTFLOAT* zone, const char* key, const char* val)
+ {
+ // Keep metadata
+ fCurrentMetadata[key] = val;
+
+ if (strcmp(key, "scale") == 0) {
+ if (strcmp(val, "log") == 0) {
+ fCurrentScale = kLog;
+ } else if (strcmp(val, "exp") == 0) {
+ fCurrentScale = kExp;
+ } else {
+ fCurrentScale = kLin;
+ }
+ } else if (strcmp(key, "unit") == 0) {
+ fCurrentUnit = val;
+ } else if (strcmp(key, "acc") == 0) {
+ fCurrentAcc = val;
+ } else if (strcmp(key, "gyr") == 0) {
+ fCurrentGyr = val;
+ } else if (strcmp(key, "screencolor") == 0) {
+ fCurrentColor = val; // val = "red", "green", "blue" or "white"
+ } else if (strcmp(key, "tooltip") == 0) {
+ fCurrentTooltip = val;
+ }
+ }
+
+ virtual void declare(const char* key, const char* val)
+ {}
+
+ //-------------------------------------------------------------------------------
+ // Simple API part
+ //-------------------------------------------------------------------------------
+ int getParamsCount() { return fNumParameters; }
+ int getParamIndex(const char* path)
+ {
+ if (fPathMap.find(path) != fPathMap.end()) {
+ return fPathMap[path];
+ } else if (fLabelMap.find(path) != fLabelMap.end()) {
+ return fLabelMap[path];
+ } else {
+ return -1;
+ }
+ }
+ const char* getParamAddress(int p) { return fPaths[p].c_str(); }
+ const char* getParamLabel(int p) { return fLabels[p].c_str(); }
+ std::map<const char*, const char*> getMetadata(int p)
+ {
+ std::map<const char*, const char*> res;
+ std::map<std::string, std::string> metadata = fMetaData[p];
+ for (auto it : metadata) {
+ res[it.first.c_str()] = it.second.c_str();
+ }
+ return res;
+ }
+
+ const char* getMetadata(int p, const char* key)
+ {
+ return (fMetaData[p].find(key) != fMetaData[p].end()) ? fMetaData[p][key].c_str() : "";
+ }
+ FAUSTFLOAT getParamMin(int p) { return fMin[p]; }
+ FAUSTFLOAT getParamMax(int p) { return fMax[p]; }
+ FAUSTFLOAT getParamStep(int p) { return fStep[p]; }
+ FAUSTFLOAT getParamInit(int p) { return fInit[p]; }
+
+ FAUSTFLOAT* getParamZone(int p) { return fZone[p]; }
+ FAUSTFLOAT getParamValue(int p) { return *fZone[p]; }
+ void setParamValue(int p, FAUSTFLOAT v) { *fZone[p] = v; }
+
+ double getParamRatio(int p) { return fConversion[p]->faust2ui(*fZone[p]); }
+ void setParamRatio(int p, double r) { *fZone[p] = fConversion[p]->ui2faust(r); }
+
+ double value2ratio(int p, double r) { return fConversion[p]->faust2ui(r); }
+ double ratio2value(int p, double r) { return fConversion[p]->ui2faust(r); }
+
+ /**
+ * Return the control type (kAcc, kGyr, or -1) for a given parameter
+ *
+ * @param p - the UI parameter index
+ *
+ * @return the type
+ */
+ Type getParamType(int p)
+ {
+ if (p >= 0) {
+ if (getZoneIndex(fAcc, p, 0) != -1
+ || getZoneIndex(fAcc, p, 1) != -1
+ || getZoneIndex(fAcc, p, 2) != -1) {
+ return kAcc;
+ } else if (getZoneIndex(fGyr, p, 0) != -1
+ || getZoneIndex(fGyr, p, 1) != -1
+ || getZoneIndex(fGyr, p, 2) != -1) {
+ return kGyr;
+ }
+ }
+ return kNoType;
+ }
+
+ /**
+ * Return the Item type (kButton = 0, kCheckButton, kVSlider, kHSlider, kNumEntry, kHBargraph, kVBargraph) for a given parameter
+ *
+ * @param p - the UI parameter index
+ *
+ * @return the Item type
+ */
+ ItemType getParamItemType(int p)
+ {
+ return fItemType[p];
+ }
+
+ /**
+ * Set a new value coming from an accelerometer, propagate it to all relevant FAUSTFLOAT* zones.
+ *
+ * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+ * @param value - the new value
+ *
+ */
+ void propagateAcc(int acc, double value)
+ {
+ for (size_t i = 0; i < fAcc[acc].size(); i++) {
+ fAcc[acc][i]->update(value);
+ }
+ }
+
+ /**
+ * Used to edit accelerometer curves and mapping. Set curve and related mapping for a given UI parameter.
+ *
+ * @param p - the UI parameter index
+ * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer (-1 means "no mapping")
+ * @param curve - between 0 and 3
+ * @param amin - mapping 'min' point
+ * @param amid - mapping 'middle' point
+ * @param amax - mapping 'max' point
+ *
+ */
+ void setAccConverter(int p, int acc, int curve, double amin, double amid, double amax)
+ {
+ setConverter(fAcc, p, acc, curve, amin, amid, amax);
+ }
+
+ /**
+ * Used to edit gyroscope curves and mapping. Set curve and related mapping for a given UI parameter.
+ *
+ * @param p - the UI parameter index
+ * @param acc - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope (-1 means "no mapping")
+ * @param curve - between 0 and 3
+ * @param amin - mapping 'min' point
+ * @param amid - mapping 'middle' point
+ * @param amax - mapping 'max' point
+ *
+ */
+ void setGyrConverter(int p, int gyr, int curve, double amin, double amid, double amax)
+ {
+ setConverter(fGyr, p, gyr, curve, amin, amid, amax);
+ }
+
+ /**
+ * Used to edit accelerometer curves and mapping. Get curve and related mapping for a given UI parameter.
+ *
+ * @param p - the UI parameter index
+ * @param acc - the acc value to be retrieved (-1 means "no mapping")
+ * @param curve - the curve value to be retrieved
+ * @param amin - the amin value to be retrieved
+ * @param amid - the amid value to be retrieved
+ * @param amax - the amax value to be retrieved
+ *
+ */
+ void getAccConverter(int p, int& acc, int& curve, double& amin, double& amid, double& amax)
+ {
+ getConverter(fAcc, p, acc, curve, amin, amid, amax);
+ }
+
+ /**
+ * Used to edit gyroscope curves and mapping. Get curve and related mapping for a given UI parameter.
+ *
+ * @param p - the UI parameter index
+ * @param gyr - the gyr value to be retrieved (-1 means "no mapping")
+ * @param curve - the curve value to be retrieved
+ * @param amin - the amin value to be retrieved
+ * @param amid - the amid value to be retrieved
+ * @param amax - the amax value to be retrieved
+ *
+ */
+ void getGyrConverter(int p, int& gyr, int& curve, double& amin, double& amid, double& amax)
+ {
+ getConverter(fGyr, p, gyr, curve, amin, amid, amax);
+ }
+
+ /**
+ * Set a new value coming from an gyroscope, propagate it to all relevant FAUSTFLOAT* zones.
+ *
+ * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
+ * @param value - the new value
+ *
+ */
+ void propagateGyr(int gyr, double value)
+ {
+ for (size_t i = 0; i < fGyr[gyr].size(); i++) {
+ fGyr[gyr][i]->update(value);
+ }
+ }
+
+ /**
+ * Get the number of FAUSTFLOAT* zones controlled with the accelerometer
+ *
+ * @param acc - 0 for X accelerometer, 1 for Y accelerometer, 2 for Z accelerometer
+ * @return the number of zones
+ *
+ */
+ int getAccCount(int acc)
+ {
+ return (acc >= 0 && acc < 3) ? int(fAcc[acc].size()) : 0;
+ }
+
+ /**
+ * Get the number of FAUSTFLOAT* zones controlled with the gyroscope
+ *
+ * @param gyr - 0 for X gyroscope, 1 for Y gyroscope, 2 for Z gyroscope
+ * @param the number of zones
+ *
+ */
+ int getGyrCount(int gyr)
+ {
+ return (gyr >= 0 && gyr < 3) ? int(fGyr[gyr].size()) : 0;
+ }
+
+ // getScreenColor() : -1 means no screen color control (no screencolor metadata found)
+ // otherwise return 0x00RRGGBB a ready to use color
+ int getScreenColor()
+ {
+ if (fHasScreenControl) {
+ int r = (fRedReader) ? fRedReader->getValue() : 0;
+ int g = (fGreenReader) ? fGreenReader->getValue() : 0;
+ int b = (fBlueReader) ? fBlueReader->getValue() : 0;
+ return (r<<16) | (g<<8) | b;
+ } else {
+ return -1;
+ }
+ }
+
+};
+
+#endif
+/************************** END APIUI.h **************************/
+
+// NOTE: "faust -scn name" changes the last line above to
+// #include <faust/name/name.h>
+
+//----------------------------------------------------------------------------
+// FAUST Generated Code
+//----------------------------------------------------------------------------
+
+
+#ifndef FAUSTFLOAT
+#define FAUSTFLOAT float
+#endif
+
+#include <algorithm>
+#include <cmath>
+#include <math.h>
+
+static float zitarevmonodsp_faustpower2_f(float value) {
+ return (value * value);
+}
+
+#ifndef FAUSTCLASS
+#define FAUSTCLASS zitarevmonodsp
+#endif
+
+#ifdef __APPLE__
+#define exp10f __exp10f
+#define exp10 __exp10
+#endif
+
+class zitarevmonodsp : public dsp {
+
+ private:
+
+ int IOTA;
+ float fVec0[16384];
+ FAUSTFLOAT fVslider0;
+ float fRec0[2];
+ FAUSTFLOAT fVslider1;
+ float fRec1[2];
+ int fSampleRate;
+ float fConst0;
+ float fConst1;
+ FAUSTFLOAT fVslider2;
+ FAUSTFLOAT fVslider3;
+ FAUSTFLOAT fVslider4;
+ FAUSTFLOAT fVslider5;
+ float fConst2;
+ float fConst3;
+ FAUSTFLOAT fVslider6;
+ FAUSTFLOAT fVslider7;
+ FAUSTFLOAT fVslider8;
+ float fConst4;
+ FAUSTFLOAT fVslider9;
+ float fRec15[2];
+ float fRec14[2];
+ float fVec1[32768];
+ float fConst5;
+ int iConst6;
+ float fConst7;
+ FAUSTFLOAT fVslider10;
+ float fVec2[2048];
+ int iConst8;
+ float fRec12[2];
+ float fConst9;
+ float fConst10;
+ float fRec19[2];
+ float fRec18[2];
+ float fVec3[32768];
+ float fConst11;
+ int iConst12;
+ float fVec4[4096];
+ int iConst13;
+ float fRec16[2];
+ float fConst14;
+ float fConst15;
+ float fRec23[2];
+ float fRec22[2];
+ float fVec5[16384];
+ float fConst16;
+ int iConst17;
+ float fVec6[4096];
+ int iConst18;
+ float fRec20[2];
+ float fConst19;
+ float fConst20;
+ float fRec27[2];
+ float fRec26[2];
+ float fVec7[32768];
+ float fConst21;
+ int iConst22;
+ float fVec8[4096];
+ int iConst23;
+ float fRec24[2];
+ float fConst24;
+ float fConst25;
+ float fRec31[2];
+ float fRec30[2];
+ float fVec9[16384];
+ float fConst26;
+ int iConst27;
+ float fVec10[2048];
+ int iConst28;
+ float fRec28[2];
+ float fConst29;
+ float fConst30;
+ float fRec35[2];
+ float fRec34[2];
+ float fVec11[16384];
+ float fConst31;
+ int iConst32;
+ float fVec12[4096];
+ int iConst33;
+ float fRec32[2];
+ float fConst34;
+ float fConst35;
+ float fRec39[2];
+ float fRec38[2];
+ float fVec13[16384];
+ float fConst36;
+ int iConst37;
+ float fVec14[4096];
+ int iConst38;
+ float fRec36[2];
+ float fConst39;
+ float fConst40;
+ float fRec43[2];
+ float fRec42[2];
+ float fVec15[16384];
+ float fConst41;
+ int iConst42;
+ float fVec16[2048];
+ int iConst43;
+ float fRec40[2];
+ float fRec4[3];
+ float fRec5[3];
+ float fRec6[3];
+ float fRec7[3];
+ float fRec8[3];
+ float fRec9[3];
+ float fRec10[3];
+ float fRec11[3];
+ float fRec3[3];
+ float fRec2[3];
+ float fRec45[3];
+ float fRec44[3];
+
+ public:
+
+ void metadata(Meta* m) {
+ m->declare("basics.lib/name", "Faust Basic Element Library");
+ m->declare("basics.lib/version", "0.1");
+ m->declare("delays.lib/name", "Faust Delay Library");
+ m->declare("delays.lib/version", "0.1");
+ m->declare("filename", "zitarevmonodsp.dsp");
+ m->declare("filters.lib/allpass_comb:author", "Julius O. Smith III");
+ m->declare("filters.lib/allpass_comb:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+ m->declare("filters.lib/allpass_comb:license", "MIT-style STK-4.3 license");
+ m->declare("filters.lib/fir:author", "Julius O. Smith III");
+ m->declare("filters.lib/fir:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+ m->declare("filters.lib/fir:license", "MIT-style STK-4.3 license");
+ m->declare("filters.lib/iir:author", "Julius O. Smith III");
+ m->declare("filters.lib/iir:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+ m->declare("filters.lib/iir:license", "MIT-style STK-4.3 license");
+ m->declare("filters.lib/lowpass0_highpass1", "MIT-style STK-4.3 license");
+ m->declare("filters.lib/lowpass0_highpass1:author", "Julius O. Smith III");
+ m->declare("filters.lib/lowpass:author", "Julius O. Smith III");
+ m->declare("filters.lib/lowpass:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+ m->declare("filters.lib/lowpass:license", "MIT-style STK-4.3 license");
+ m->declare("filters.lib/name", "Faust Filters Library");
+ m->declare("filters.lib/peak_eq_rm:author", "Julius O. Smith III");
+ m->declare("filters.lib/peak_eq_rm:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+ m->declare("filters.lib/peak_eq_rm:license", "MIT-style STK-4.3 license");
+ m->declare("filters.lib/tf1:author", "Julius O. Smith III");
+ m->declare("filters.lib/tf1:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+ m->declare("filters.lib/tf1:license", "MIT-style STK-4.3 license");
+ m->declare("filters.lib/tf1s:author", "Julius O. Smith III");
+ m->declare("filters.lib/tf1s:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+ m->declare("filters.lib/tf1s:license", "MIT-style STK-4.3 license");
+ m->declare("filters.lib/tf2:author", "Julius O. Smith III");
+ m->declare("filters.lib/tf2:copyright", "Copyright (C) 2003-2019 by Julius O. Smith III <jos@ccrma.stanford.edu>");
+ m->declare("filters.lib/tf2:license", "MIT-style STK-4.3 license");
+ m->declare("maths.lib/author", "GRAME");
+ m->declare("maths.lib/copyright", "GRAME");
+ m->declare("maths.lib/license", "LGPL with exception");
+ m->declare("maths.lib/name", "Faust Math Library");
+ m->declare("maths.lib/version", "2.3");
+ m->declare("name", "zitarevmonodsp");
+ m->declare("platform.lib/name", "Generic Platform Library");
+ m->declare("platform.lib/version", "0.1");
+ m->declare("reverbs.lib/name", "Faust Reverb Library");
+ m->declare("reverbs.lib/version", "0.0");
+ m->declare("routes.lib/name", "Faust Signal Routing Library");
+ m->declare("routes.lib/version", "0.2");
+ m->declare("signals.lib/name", "Faust Signal Routing Library");
+ m->declare("signals.lib/version", "0.0");
+ }
+
+ virtual int getNumInputs() {
+ return 1;
+ }
+ virtual int getNumOutputs() {
+ return 1;
+ }
+ virtual int getInputRate(int channel) {
+ int rate;
+ switch ((channel)) {
+ case 0: {
+ rate = 1;
+ break;
+ }
+ default: {
+ rate = -1;
+ break;
+ }
+ }
+ return rate;
+ }
+ virtual int getOutputRate(int channel) {
+ int rate;
+ switch ((channel)) {
+ case 0: {
+ rate = 1;
+ break;
+ }
+ default: {
+ rate = -1;
+ break;
+ }
+ }
+ return rate;
+ }
+
+ static void classInit(int sample_rate) {
+ }
+
+ virtual void instanceConstants(int sample_rate) {
+ fSampleRate = sample_rate;
+ fConst0 = std::min<float>(192000.0f, std::max<float>(1.0f, float(fSampleRate)));
+ fConst1 = (6.28318548f / fConst0);
+ fConst2 = std::floor(((0.219990999f * fConst0) + 0.5f));
+ fConst3 = ((0.0f - (6.90775537f * fConst2)) / fConst0);
+ fConst4 = (3.14159274f / fConst0);
+ fConst5 = std::floor(((0.0191229992f * fConst0) + 0.5f));
+ iConst6 = int(std::min<float>(16384.0f, std::max<float>(0.0f, (fConst2 - fConst5))));
+ fConst7 = (0.00100000005f * fConst0);
+ iConst8 = int(std::min<float>(1024.0f, std::max<float>(0.0f, (fConst5 + -1.0f))));
+ fConst9 = std::floor(((0.256891012f * fConst0) + 0.5f));
+ fConst10 = ((0.0f - (6.90775537f * fConst9)) / fConst0);
+ fConst11 = std::floor(((0.0273330007f * fConst0) + 0.5f));
+ iConst12 = int(std::min<float>(16384.0f, std::max<float>(0.0f, (fConst9 - fConst11))));
+ iConst13 = int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst11 + -1.0f))));
+ fConst14 = std::floor(((0.192303002f * fConst0) + 0.5f));
+ fConst15 = ((0.0f - (6.90775537f * fConst14)) / fConst0);
+ fConst16 = std::floor(((0.0292910002f * fConst0) + 0.5f));
+ iConst17 = int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst14 - fConst16))));
+ iConst18 = int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst16 + -1.0f))));
+ fConst19 = std::floor(((0.210389003f * fConst0) + 0.5f));
+ fConst20 = ((0.0f - (6.90775537f * fConst19)) / fConst0);
+ fConst21 = std::floor(((0.0244210009f * fConst0) + 0.5f));
+ iConst22 = int(std::min<float>(16384.0f, std::max<float>(0.0f, (fConst19 - fConst21))));
+ iConst23 = int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst21 + -1.0f))));
+ fConst24 = std::floor(((0.125f * fConst0) + 0.5f));
+ fConst25 = ((0.0f - (6.90775537f * fConst24)) / fConst0);
+ fConst26 = std::floor(((0.0134579996f * fConst0) + 0.5f));
+ iConst27 = int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst24 - fConst26))));
+ iConst28 = int(std::min<float>(1024.0f, std::max<float>(0.0f, (fConst26 + -1.0f))));
+ fConst29 = std::floor(((0.127837002f * fConst0) + 0.5f));
+ fConst30 = ((0.0f - (6.90775537f * fConst29)) / fConst0);
+ fConst31 = std::floor(((0.0316039994f * fConst0) + 0.5f));
+ iConst32 = int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst29 - fConst31))));
+ iConst33 = int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst31 + -1.0f))));
+ fConst34 = std::floor(((0.174713001f * fConst0) + 0.5f));
+ fConst35 = ((0.0f - (6.90775537f * fConst34)) / fConst0);
+ fConst36 = std::floor(((0.0229039993f * fConst0) + 0.5f));
+ iConst37 = int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst34 - fConst36))));
+ iConst38 = int(std::min<float>(2048.0f, std::max<float>(0.0f, (fConst36 + -1.0f))));
+ fConst39 = std::floor(((0.153128996f * fConst0) + 0.5f));
+ fConst40 = ((0.0f - (6.90775537f * fConst39)) / fConst0);
+ fConst41 = std::floor(((0.0203460008f * fConst0) + 0.5f));
+ iConst42 = int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst39 - fConst41))));
+ iConst43 = int(std::min<float>(1024.0f, std::max<float>(0.0f, (fConst41 + -1.0f))));
+ }
+
+ virtual void instanceResetUserInterface() {
+ fVslider0 = FAUSTFLOAT(-3.0f);
+ fVslider1 = FAUSTFLOAT(0.0f);
+ fVslider2 = FAUSTFLOAT(1500.0f);
+ fVslider3 = FAUSTFLOAT(0.0f);
+ fVslider4 = FAUSTFLOAT(315.0f);
+ fVslider5 = FAUSTFLOAT(0.0f);
+ fVslider6 = FAUSTFLOAT(2.0f);
+ fVslider7 = FAUSTFLOAT(6000.0f);
+ fVslider8 = FAUSTFLOAT(3.0f);
+ fVslider9 = FAUSTFLOAT(200.0f);
+ fVslider10 = FAUSTFLOAT(60.0f);
+ }
+
+ virtual void instanceClear() {
+ IOTA = 0;
+ for (int l0 = 0; (l0 < 16384); l0 = (l0 + 1)) {
+ fVec0[l0] = 0.0f;
+ }
+ for (int l1 = 0; (l1 < 2); l1 = (l1 + 1)) {
+ fRec0[l1] = 0.0f;
+ }
+ for (int l2 = 0; (l2 < 2); l2 = (l2 + 1)) {
+ fRec1[l2] = 0.0f;
+ }
+ for (int l3 = 0; (l3 < 2); l3 = (l3 + 1)) {
+ fRec15[l3] = 0.0f;
+ }
+ for (int l4 = 0; (l4 < 2); l4 = (l4 + 1)) {
+ fRec14[l4] = 0.0f;
+ }
+ for (int l5 = 0; (l5 < 32768); l5 = (l5 + 1)) {
+ fVec1[l5] = 0.0f;
+ }
+ for (int l6 = 0; (l6 < 2048); l6 = (l6 + 1)) {
+ fVec2[l6] = 0.0f;
+ }
+ for (int l7 = 0; (l7 < 2); l7 = (l7 + 1)) {
+ fRec12[l7] = 0.0f;
+ }
+ for (int l8 = 0; (l8 < 2); l8 = (l8 + 1)) {
+ fRec19[l8] = 0.0f;
+ }
+ for (int l9 = 0; (l9 < 2); l9 = (l9 + 1)) {
+ fRec18[l9] = 0.0f;
+ }
+ for (int l10 = 0; (l10 < 32768); l10 = (l10 + 1)) {
+ fVec3[l10] = 0.0f;
+ }
+ for (int l11 = 0; (l11 < 4096); l11 = (l11 + 1)) {
+ fVec4[l11] = 0.0f;
+ }
+ for (int l12 = 0; (l12 < 2); l12 = (l12 + 1)) {
+ fRec16[l12] = 0.0f;
+ }
+ for (int l13 = 0; (l13 < 2); l13 = (l13 + 1)) {
+ fRec23[l13] = 0.0f;
+ }
+ for (int l14 = 0; (l14 < 2); l14 = (l14 + 1)) {
+ fRec22[l14] = 0.0f;
+ }
+ for (int l15 = 0; (l15 < 16384); l15 = (l15 + 1)) {
+ fVec5[l15] = 0.0f;
+ }
+ for (int l16 = 0; (l16 < 4096); l16 = (l16 + 1)) {
+ fVec6[l16] = 0.0f;
+ }
+ for (int l17 = 0; (l17 < 2); l17 = (l17 + 1)) {
+ fRec20[l17] = 0.0f;
+ }
+ for (int l18 = 0; (l18 < 2); l18 = (l18 + 1)) {
+ fRec27[l18] = 0.0f;
+ }
+ for (int l19 = 0; (l19 < 2); l19 = (l19 + 1)) {
+ fRec26[l19] = 0.0f;
+ }
+ for (int l20 = 0; (l20 < 32768); l20 = (l20 + 1)) {
+ fVec7[l20] = 0.0f;
+ }
+ for (int l21 = 0; (l21 < 4096); l21 = (l21 + 1)) {
+ fVec8[l21] = 0.0f;
+ }
+ for (int l22 = 0; (l22 < 2); l22 = (l22 + 1)) {
+ fRec24[l22] = 0.0f;
+ }
+ for (int l23 = 0; (l23 < 2); l23 = (l23 + 1)) {
+ fRec31[l23] = 0.0f;
+ }
+ for (int l24 = 0; (l24 < 2); l24 = (l24 + 1)) {
+ fRec30[l24] = 0.0f;
+ }
+ for (int l25 = 0; (l25 < 16384); l25 = (l25 + 1)) {
+ fVec9[l25] = 0.0f;
+ }
+ for (int l26 = 0; (l26 < 2048); l26 = (l26 + 1)) {
+ fVec10[l26] = 0.0f;
+ }
+ for (int l27 = 0; (l27 < 2); l27 = (l27 + 1)) {
+ fRec28[l27] = 0.0f;
+ }
+ for (int l28 = 0; (l28 < 2); l28 = (l28 + 1)) {
+ fRec35[l28] = 0.0f;
+ }
+ for (int l29 = 0; (l29 < 2); l29 = (l29 + 1)) {
+ fRec34[l29] = 0.0f;
+ }
+ for (int l30 = 0; (l30 < 16384); l30 = (l30 + 1)) {
+ fVec11[l30] = 0.0f;
+ }
+ for (int l31 = 0; (l31 < 4096); l31 = (l31 + 1)) {
+ fVec12[l31] = 0.0f;
+ }
+ for (int l32 = 0; (l32 < 2); l32 = (l32 + 1)) {
+ fRec32[l32] = 0.0f;
+ }
+ for (int l33 = 0; (l33 < 2); l33 = (l33 + 1)) {
+ fRec39[l33] = 0.0f;
+ }
+ for (int l34 = 0; (l34 < 2); l34 = (l34 + 1)) {
+ fRec38[l34] = 0.0f;
+ }
+ for (int l35 = 0; (l35 < 16384); l35 = (l35 + 1)) {
+ fVec13[l35] = 0.0f;
+ }
+ for (int l36 = 0; (l36 < 4096); l36 = (l36 + 1)) {
+ fVec14[l36] = 0.0f;
+ }
+ for (int l37 = 0; (l37 < 2); l37 = (l37 + 1)) {
+ fRec36[l37] = 0.0f;
+ }
+ for (int l38 = 0; (l38 < 2); l38 = (l38 + 1)) {
+ fRec43[l38] = 0.0f;
+ }
+ for (int l39 = 0; (l39 < 2); l39 = (l39 + 1)) {
+ fRec42[l39] = 0.0f;
+ }
+ for (int l40 = 0; (l40 < 16384); l40 = (l40 + 1)) {
+ fVec15[l40] = 0.0f;
+ }
+ for (int l41 = 0; (l41 < 2048); l41 = (l41 + 1)) {
+ fVec16[l41] = 0.0f;
+ }
+ for (int l42 = 0; (l42 < 2); l42 = (l42 + 1)) {
+ fRec40[l42] = 0.0f;
+ }
+ for (int l43 = 0; (l43 < 3); l43 = (l43 + 1)) {
+ fRec4[l43] = 0.0f;
+ }
+ for (int l44 = 0; (l44 < 3); l44 = (l44 + 1)) {
+ fRec5[l44] = 0.0f;
+ }
+ for (int l45 = 0; (l45 < 3); l45 = (l45 + 1)) {
+ fRec6[l45] = 0.0f;
+ }
+ for (int l46 = 0; (l46 < 3); l46 = (l46 + 1)) {
+ fRec7[l46] = 0.0f;
+ }
+ for (int l47 = 0; (l47 < 3); l47 = (l47 + 1)) {
+ fRec8[l47] = 0.0f;
+ }
+ for (int l48 = 0; (l48 < 3); l48 = (l48 + 1)) {
+ fRec9[l48] = 0.0f;
+ }
+ for (int l49 = 0; (l49 < 3); l49 = (l49 + 1)) {
+ fRec10[l49] = 0.0f;
+ }
+ for (int l50 = 0; (l50 < 3); l50 = (l50 + 1)) {
+ fRec11[l50] = 0.0f;
+ }
+ for (int l51 = 0; (l51 < 3); l51 = (l51 + 1)) {
+ fRec3[l51] = 0.0f;
+ }
+ for (int l52 = 0; (l52 < 3); l52 = (l52 + 1)) {
+ fRec2[l52] = 0.0f;
+ }
+ for (int l53 = 0; (l53 < 3); l53 = (l53 + 1)) {
+ fRec45[l53] = 0.0f;
+ }
+ for (int l54 = 0; (l54 < 3); l54 = (l54 + 1)) {
+ fRec44[l54] = 0.0f;
+ }
+ }
+
+ virtual void init(int sample_rate) {
+ classInit(sample_rate);
+ instanceInit(sample_rate);
+ }
+ virtual void instanceInit(int sample_rate) {
+ instanceConstants(sample_rate);
+ instanceResetUserInterface();
+ instanceClear();
+ }
+
+ virtual zitarevmonodsp* clone() {
+ return new zitarevmonodsp();
+ }
+
+ virtual int getSampleRate() {
+ return fSampleRate;
+ }
+
+ virtual void buildUserInterface(UI* ui_interface) {
+ ui_interface->declare(0, "0", "");
+ ui_interface->declare(0, "tooltip", "~ ZITA REV1 FEEDBACK DELAY NETWORK (FDN) & SCHROEDER ALLPASS-COMB REVERBERATOR (8x8). See Faust's reverbs.lib for documentation and references");
+ ui_interface->openHorizontalBox("Zita_Rev1");
+ ui_interface->declare(0, "1", "");
+ ui_interface->openHorizontalBox("Input");
+ ui_interface->declare(&fVslider10, "1", "");
+ ui_interface->declare(&fVslider10, "style", "knob");
+ ui_interface->declare(&fVslider10, "tooltip", "Delay in ms before reverberation begins");
+ ui_interface->declare(&fVslider10, "unit", "ms");
+ ui_interface->addVerticalSlider("In Delay", &fVslider10, 60.0f, 20.0f, 100.0f, 1.0f);
+ ui_interface->closeBox();
+ ui_interface->declare(0, "2", "");
+ ui_interface->openHorizontalBox("Decay Times in Bands (see tooltips)");
+ ui_interface->declare(&fVslider9, "1", "");
+ ui_interface->declare(&fVslider9, "scale", "log");
+ ui_interface->declare(&fVslider9, "style", "knob");
+ ui_interface->declare(&fVslider9, "tooltip", "Crossover frequency (Hz) separating low and middle frequencies");
+ ui_interface->declare(&fVslider9, "unit", "Hz");
+ ui_interface->addVerticalSlider("LF X", &fVslider9, 200.0f, 50.0f, 1000.0f, 1.0f);
+ ui_interface->declare(&fVslider8, "2", "");
+ ui_interface->declare(&fVslider8, "scale", "log");
+ ui_interface->declare(&fVslider8, "style", "knob");
+ ui_interface->declare(&fVslider8, "tooltip", "T60 = time (in seconds) to decay 60dB in low-frequency band");
+ ui_interface->declare(&fVslider8, "unit", "s");
+ ui_interface->addVerticalSlider("Low RT60", &fVslider8, 3.0f, 1.0f, 8.0f, 0.100000001f);
+ ui_interface->declare(&fVslider6, "3", "");
+ ui_interface->declare(&fVslider6, "scale", "log");
+ ui_interface->declare(&fVslider6, "style", "knob");
+ ui_interface->declare(&fVslider6, "tooltip", "T60 = time (in seconds) to decay 60dB in middle band");
+ ui_interface->declare(&fVslider6, "unit", "s");
+ ui_interface->addVerticalSlider("Mid RT60", &fVslider6, 2.0f, 1.0f, 8.0f, 0.100000001f);
+ ui_interface->declare(&fVslider7, "4", "");
+ ui_interface->declare(&fVslider7, "scale", "log");
+ ui_interface->declare(&fVslider7, "style", "knob");
+ ui_interface->declare(&fVslider7, "tooltip", "Frequency (Hz) at which the high-frequency T60 is half the middle-band's T60");
+ ui_interface->declare(&fVslider7, "unit", "Hz");
+ ui_interface->addVerticalSlider("HF Damping", &fVslider7, 6000.0f, 1500.0f, 23520.0f, 1.0f);
+ ui_interface->closeBox();
+ ui_interface->declare(0, "3", "");
+ ui_interface->openHorizontalBox("RM Peaking Equalizer 1");
+ ui_interface->declare(&fVslider4, "1", "");
+ ui_interface->declare(&fVslider4, "scale", "log");
+ ui_interface->declare(&fVslider4, "style", "knob");
+ ui_interface->declare(&fVslider4, "tooltip", "Center-frequency of second-order Regalia-Mitra peaking equalizer section 1");
+ ui_interface->declare(&fVslider4, "unit", "Hz");
+ ui_interface->addVerticalSlider("Eq1 Freq", &fVslider4, 315.0f, 40.0f, 2500.0f, 1.0f);
+ ui_interface->declare(&fVslider5, "2", "");
+ ui_interface->declare(&fVslider5, "style", "knob");
+ ui_interface->declare(&fVslider5, "tooltip", "Peak level in dB of second-order Regalia-Mitra peaking equalizer section 1");
+ ui_interface->declare(&fVslider5, "unit", "dB");
+ ui_interface->addVerticalSlider("Eq1 Level", &fVslider5, 0.0f, -15.0f, 15.0f, 0.100000001f);
+ ui_interface->closeBox();
+ ui_interface->declare(0, "4", "");
+ ui_interface->openHorizontalBox("RM Peaking Equalizer 2");
+ ui_interface->declare(&fVslider2, "1", "");
+ ui_interface->declare(&fVslider2, "scale", "log");
+ ui_interface->declare(&fVslider2, "style", "knob");
+ ui_interface->declare(&fVslider2, "tooltip", "Center-frequency of second-order Regalia-Mitra peaking equalizer section 2");
+ ui_interface->declare(&fVslider2, "unit", "Hz");
+ ui_interface->addVerticalSlider("Eq2 Freq", &fVslider2, 1500.0f, 160.0f, 10000.0f, 1.0f);
+ ui_interface->declare(&fVslider3, "2", "");
+ ui_interface->declare(&fVslider3, "style", "knob");
+ ui_interface->declare(&fVslider3, "tooltip", "Peak level in dB of second-order Regalia-Mitra peaking equalizer section 2");
+ ui_interface->declare(&fVslider3, "unit", "dB");
+ ui_interface->addVerticalSlider("Eq2 Level", &fVslider3, 0.0f, -15.0f, 15.0f, 0.100000001f);
+ ui_interface->closeBox();
+ ui_interface->declare(0, "5", "");
+ ui_interface->openHorizontalBox("Output");
+ ui_interface->declare(&fVslider1, "1", "");
+ ui_interface->declare(&fVslider1, "style", "knob");
+ ui_interface->declare(&fVslider1, "tooltip", "Dry/Wet Mix: 0 = dry, 1 = wet");
+ ui_interface->addVerticalSlider("Wet", &fVslider1, 0.0f, 0.0f, 1.0f, 0.00999999978f);
+ ui_interface->declare(&fVslider0, "2", "");
+ ui_interface->declare(&fVslider0, "style", "knob");
+ ui_interface->declare(&fVslider0, "tooltip", "Output scale factor");
+ ui_interface->declare(&fVslider0, "unit", "dB");
+ ui_interface->addVerticalSlider("Level", &fVslider0, -3.0f, -70.0f, 20.0f, 0.100000001f);
+ ui_interface->closeBox();
+ ui_interface->closeBox();
+ }
+
+ virtual void compute(int count, FAUSTFLOAT** inputs, FAUSTFLOAT** outputs) {
+ FAUSTFLOAT* input0 = inputs[0];
+ FAUSTFLOAT* output0 = outputs[0];
+ float fSlow0 = (0.00100000005f * std::pow(10.0f, (0.0500000007f * float(fVslider0))));
+ float fSlow1 = (0.00100000005f * float(fVslider1));
+ float fSlow2 = float(fVslider2);
+ float fSlow3 = std::pow(10.0f, (0.0500000007f * float(fVslider3)));
+ float fSlow4 = (fConst1 * (fSlow2 / std::sqrt(std::max<float>(0.0f, fSlow3))));
+ float fSlow5 = ((1.0f - fSlow4) / (fSlow4 + 1.0f));
+ float fSlow6 = float(fVslider4);
+ float fSlow7 = std::pow(10.0f, (0.0500000007f * float(fVslider5)));
+ float fSlow8 = (fConst1 * (fSlow6 / std::sqrt(std::max<float>(0.0f, fSlow7))));
+ float fSlow9 = ((1.0f - fSlow8) / (fSlow8 + 1.0f));
+ float fSlow10 = float(fVslider6);
+ float fSlow11 = std::exp((fConst3 / fSlow10));
+ float fSlow12 = zitarevmonodsp_faustpower2_f(fSlow11);
+ float fSlow13 = std::cos((fConst1 * float(fVslider7)));
+ float fSlow14 = (1.0f - (fSlow12 * fSlow13));
+ float fSlow15 = (1.0f - fSlow12);
+ float fSlow16 = (fSlow14 / fSlow15);
+ float fSlow17 = std::sqrt(std::max<float>(0.0f, ((zitarevmonodsp_faustpower2_f(fSlow14) / zitarevmonodsp_faustpower2_f(fSlow15)) + -1.0f)));
+ float fSlow18 = (fSlow16 - fSlow17);
+ float fSlow19 = (fSlow11 * (fSlow17 + (1.0f - fSlow16)));
+ float fSlow20 = float(fVslider8);
+ float fSlow21 = ((std::exp((fConst3 / fSlow20)) / fSlow11) + -1.0f);
+ float fSlow22 = (1.0f / std::tan((fConst4 * float(fVslider9))));
+ float fSlow23 = (1.0f / (fSlow22 + 1.0f));
+ float fSlow24 = (1.0f - fSlow22);
+ int iSlow25 = int(std::min<float>(8192.0f, std::max<float>(0.0f, (fConst7 * float(fVslider10)))));
+ float fSlow26 = std::exp((fConst10 / fSlow10));
+ float fSlow27 = zitarevmonodsp_faustpower2_f(fSlow26);
+ float fSlow28 = (1.0f - (fSlow27 * fSlow13));
+ float fSlow29 = (1.0f - fSlow27);
+ float fSlow30 = (fSlow28 / fSlow29);
+ float fSlow31 = std::sqrt(std::max<float>(0.0f, ((zitarevmonodsp_faustpower2_f(fSlow28) / zitarevmonodsp_faustpower2_f(fSlow29)) + -1.0f)));
+ float fSlow32 = (fSlow30 - fSlow31);
+ float fSlow33 = (fSlow26 * (fSlow31 + (1.0f - fSlow30)));
+ float fSlow34 = ((std::exp((fConst10 / fSlow20)) / fSlow26) + -1.0f);
+ float fSlow35 = std::exp((fConst15 / fSlow10));
+ float fSlow36 = zitarevmonodsp_faustpower2_f(fSlow35);
+ float fSlow37 = (1.0f - (fSlow36 * fSlow13));
+ float fSlow38 = (1.0f - fSlow36);
+ float fSlow39 = (fSlow37 / fSlow38);
+ float fSlow40 = std::sqrt(std::max<float>(0.0f, ((zitarevmonodsp_faustpower2_f(fSlow37) / zitarevmonodsp_faustpower2_f(fSlow38)) + -1.0f)));
+ float fSlow41 = (fSlow39 - fSlow40);
+ float fSlow42 = (fSlow35 * (fSlow40 + (1.0f - fSlow39)));
+ float fSlow43 = ((std::exp((fConst15 / fSlow20)) / fSlow35) + -1.0f);
+ float fSlow44 = std::exp((fConst20 / fSlow10));
+ float fSlow45 = zitarevmonodsp_faustpower2_f(fSlow44);
+ float fSlow46 = (1.0f - (fSlow45 * fSlow13));
+ float fSlow47 = (1.0f - fSlow45);
+ float fSlow48 = (fSlow46 / fSlow47);
+ float fSlow49 = std::sqrt(std::max<float>(0.0f, ((zitarevmonodsp_faustpower2_f(fSlow46) / zitarevmonodsp_faustpower2_f(fSlow47)) + -1.0f)));
+ float fSlow50 = (fSlow48 - fSlow49);
+ float fSlow51 = (fSlow44 * (fSlow49 + (1.0f - fSlow48)));
+ float fSlow52 = ((std::exp((fConst20 / fSlow20)) / fSlow44) + -1.0f);
+ float fSlow53 = std::exp((fConst25 / fSlow10));
+ float fSlow54 = zitarevmonodsp_faustpower2_f(fSlow53);
+ float fSlow55 = (1.0f - (fSlow54 * fSlow13));
+ float fSlow56 = (1.0f - fSlow54);
+ float fSlow57 = (fSlow55 / fSlow56);
+ float fSlow58 = std::sqrt(std::max<float>(0.0f, ((zitarevmonodsp_faustpower2_f(fSlow55) / zitarevmonodsp_faustpower2_f(fSlow56)) + -1.0f)));
+ float fSlow59 = (fSlow57 - fSlow58);
+ float fSlow60 = (fSlow53 * (fSlow58 + (1.0f - fSlow57)));
+ float fSlow61 = ((std::exp((fConst25 / fSlow20)) / fSlow53) + -1.0f);
+ float fSlow62 = std::exp((fConst30 / fSlow10));
+ float fSlow63 = zitarevmonodsp_faustpower2_f(fSlow62);
+ float fSlow64 = (1.0f - (fSlow63 * fSlow13));
+ float fSlow65 = (1.0f - fSlow63);
+ float fSlow66 = (fSlow64 / fSlow65);
+ float fSlow67 = std::sqrt(std::max<float>(0.0f, ((zitarevmonodsp_faustpower2_f(fSlow64) / zitarevmonodsp_faustpower2_f(fSlow65)) + -1.0f)));
+ float fSlow68 = (fSlow66 - fSlow67);
+ float fSlow69 = (fSlow62 * (fSlow67 + (1.0f - fSlow66)));
+ float fSlow70 = ((std::exp((fConst30 / fSlow20)) / fSlow62) + -1.0f);
+ float fSlow71 = std::exp((fConst35 / fSlow10));
+ float fSlow72 = zitarevmonodsp_faustpower2_f(fSlow71);
+ float fSlow73 = (1.0f - (fSlow72 * fSlow13));
+ float fSlow74 = (1.0f - fSlow72);
+ float fSlow75 = (fSlow73 / fSlow74);
+ float fSlow76 = std::sqrt(std::max<float>(0.0f, ((zitarevmonodsp_faustpower2_f(fSlow73) / zitarevmonodsp_faustpower2_f(fSlow74)) + -1.0f)));
+ float fSlow77 = (fSlow75 - fSlow76);
+ float fSlow78 = (fSlow71 * (fSlow76 + (1.0f - fSlow75)));
+ float fSlow79 = ((std::exp((fConst35 / fSlow20)) / fSlow71) + -1.0f);
+ float fSlow80 = std::exp((fConst40 / fSlow10));
+ float fSlow81 = zitarevmonodsp_faustpower2_f(fSlow80);
+ float fSlow82 = (1.0f - (fSlow81 * fSlow13));
+ float fSlow83 = (1.0f - fSlow81);
+ float fSlow84 = (fSlow82 / fSlow83);
+ float fSlow85 = std::sqrt(std::max<float>(0.0f, ((zitarevmonodsp_faustpower2_f(fSlow82) / zitarevmonodsp_faustpower2_f(fSlow83)) + -1.0f)));
+ float fSlow86 = (fSlow84 - fSlow85);
+ float fSlow87 = (fSlow80 * (fSlow85 + (1.0f - fSlow84)));
+ float fSlow88 = ((std::exp((fConst40 / fSlow20)) / fSlow80) + -1.0f);
+ float fSlow89 = (0.0f - (std::cos((fConst1 * fSlow6)) * (fSlow9 + 1.0f)));
+ float fSlow90 = (0.0f - (std::cos((fConst1 * fSlow2)) * (fSlow5 + 1.0f)));
+ for (int i = 0; (i < count); i = (i + 1)) {
+ float fTemp0 = float(input0[i]);
+ fVec0[(IOTA & 16383)] = fTemp0;
+ fRec0[0] = (fSlow0 + (0.999000013f * fRec0[1]));
+ fRec1[0] = (fSlow1 + (0.999000013f * fRec1[1]));
+ fRec15[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec15[1]) - (fRec11[1] + fRec11[2]))));
+ fRec14[0] = ((fSlow18 * fRec14[1]) + (fSlow19 * (fRec11[1] + (fSlow21 * fRec15[0]))));
+ fVec1[(IOTA & 32767)] = ((0.353553385f * fRec14[0]) + 9.99999968e-21f);
+ float fTemp1 = (0.300000012f * fVec0[((IOTA - iSlow25) & 16383)]);
+ float fTemp2 = (((0.600000024f * fRec12[1]) + fVec1[((IOTA - iConst6) & 32767)]) - fTemp1);
+ fVec2[(IOTA & 2047)] = fTemp2;
+ fRec12[0] = fVec2[((IOTA - iConst8) & 2047)];
+ float fRec13 = (0.0f - (0.600000024f * fTemp2));
+ fRec19[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec19[1]) - (fRec7[1] + fRec7[2]))));
+ fRec18[0] = ((fSlow32 * fRec18[1]) + (fSlow33 * (fRec7[1] + (fSlow34 * fRec19[0]))));
+ fVec3[(IOTA & 32767)] = ((0.353553385f * fRec18[0]) + 9.99999968e-21f);
+ float fTemp3 = (((0.600000024f * fRec16[1]) + fVec3[((IOTA - iConst12) & 32767)]) - fTemp1);
+ fVec4[(IOTA & 4095)] = fTemp3;
+ fRec16[0] = fVec4[((IOTA - iConst13) & 4095)];
+ float fRec17 = (0.0f - (0.600000024f * fTemp3));
+ fRec23[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec23[1]) - (fRec9[1] + fRec9[2]))));
+ fRec22[0] = ((fSlow41 * fRec22[1]) + (fSlow42 * (fRec9[1] + (fSlow43 * fRec23[0]))));
+ fVec5[(IOTA & 16383)] = ((0.353553385f * fRec22[0]) + 9.99999968e-21f);
+ float fTemp4 = (fVec5[((IOTA - iConst17) & 16383)] + (fTemp1 + (0.600000024f * fRec20[1])));
+ fVec6[(IOTA & 4095)] = fTemp4;
+ fRec20[0] = fVec6[((IOTA - iConst18) & 4095)];
+ float fRec21 = (0.0f - (0.600000024f * fTemp4));
+ fRec27[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec27[1]) - (fRec5[1] + fRec5[2]))));
+ fRec26[0] = ((fSlow50 * fRec26[1]) + (fSlow51 * (fRec5[1] + (fSlow52 * fRec27[0]))));
+ fVec7[(IOTA & 32767)] = ((0.353553385f * fRec26[0]) + 9.99999968e-21f);
+ float fTemp5 = (fVec7[((IOTA - iConst22) & 32767)] + (fTemp1 + (0.600000024f * fRec24[1])));
+ fVec8[(IOTA & 4095)] = fTemp5;
+ fRec24[0] = fVec8[((IOTA - iConst23) & 4095)];
+ float fRec25 = (0.0f - (0.600000024f * fTemp5));
+ fRec31[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec31[1]) - (fRec10[1] + fRec10[2]))));
+ fRec30[0] = ((fSlow59 * fRec30[1]) + (fSlow60 * (fRec10[1] + (fSlow61 * fRec31[0]))));
+ fVec9[(IOTA & 16383)] = ((0.353553385f * fRec30[0]) + 9.99999968e-21f);
+ float fTemp6 = (fVec9[((IOTA - iConst27) & 16383)] - (fTemp1 + (0.600000024f * fRec28[1])));
+ fVec10[(IOTA & 2047)] = fTemp6;
+ fRec28[0] = fVec10[((IOTA - iConst28) & 2047)];
+ float fRec29 = (0.600000024f * fTemp6);
+ fRec35[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec35[1]) - (fRec6[1] + fRec6[2]))));
+ fRec34[0] = ((fSlow68 * fRec34[1]) + (fSlow69 * (fRec6[1] + (fSlow70 * fRec35[0]))));
+ fVec11[(IOTA & 16383)] = ((0.353553385f * fRec34[0]) + 9.99999968e-21f);
+ float fTemp7 = (fVec11[((IOTA - iConst32) & 16383)] - (fTemp1 + (0.600000024f * fRec32[1])));
+ fVec12[(IOTA & 4095)] = fTemp7;
+ fRec32[0] = fVec12[((IOTA - iConst33) & 4095)];
+ float fRec33 = (0.600000024f * fTemp7);
+ fRec39[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec39[1]) - (fRec8[1] + fRec8[2]))));
+ fRec38[0] = ((fSlow77 * fRec38[1]) + (fSlow78 * (fRec8[1] + (fSlow79 * fRec39[0]))));
+ fVec13[(IOTA & 16383)] = ((0.353553385f * fRec38[0]) + 9.99999968e-21f);
+ float fTemp8 = ((fTemp1 + fVec13[((IOTA - iConst37) & 16383)]) - (0.600000024f * fRec36[1]));
+ fVec14[(IOTA & 4095)] = fTemp8;
+ fRec36[0] = fVec14[((IOTA - iConst38) & 4095)];
+ float fRec37 = (0.600000024f * fTemp8);
+ fRec43[0] = (0.0f - (fSlow23 * ((fSlow24 * fRec43[1]) - (fRec4[1] + fRec4[2]))));
+ fRec42[0] = ((fSlow86 * fRec42[1]) + (fSlow87 * (fRec4[1] + (fSlow88 * fRec43[0]))));
+ fVec15[(IOTA & 16383)] = ((0.353553385f * fRec42[0]) + 9.99999968e-21f);
+ float fTemp9 = ((fVec15[((IOTA - iConst42) & 16383)] + fTemp1) - (0.600000024f * fRec40[1]));
+ fVec16[(IOTA & 2047)] = fTemp9;
+ fRec40[0] = fVec16[((IOTA - iConst43) & 2047)];
+ float fRec41 = (0.600000024f * fTemp9);
+ float fTemp10 = (fRec41 + fRec37);
+ float fTemp11 = (fRec29 + (fRec33 + fTemp10));
+ fRec4[0] = (fRec12[1] + (fRec16[1] + (fRec20[1] + (fRec24[1] + (fRec28[1] + (fRec32[1] + (fRec36[1] + (fRec40[1] + (fRec13 + (fRec17 + (fRec21 + (fRec25 + fTemp11))))))))))));
+ fRec5[0] = ((fRec28[1] + (fRec32[1] + (fRec36[1] + (fRec40[1] + fTemp11)))) - (fRec12[1] + (fRec16[1] + (fRec20[1] + (fRec24[1] + (fRec13 + (fRec17 + (fRec25 + fRec21))))))));
+ float fTemp12 = (fRec33 + fRec29);
+ fRec6[0] = ((fRec20[1] + (fRec24[1] + (fRec36[1] + (fRec40[1] + (fRec21 + (fRec25 + fTemp10)))))) - (fRec12[1] + (fRec16[1] + (fRec28[1] + (fRec32[1] + (fRec13 + (fRec17 + fTemp12)))))));
+ fRec7[0] = ((fRec12[1] + (fRec16[1] + (fRec36[1] + (fRec40[1] + (fRec13 + (fRec17 + fTemp10)))))) - (fRec20[1] + (fRec24[1] + (fRec28[1] + (fRec32[1] + (fRec21 + (fRec25 + fTemp12)))))));
+ float fTemp13 = (fRec41 + fRec33);
+ float fTemp14 = (fRec37 + fRec29);
+ fRec8[0] = ((fRec16[1] + (fRec24[1] + (fRec32[1] + (fRec40[1] + (fRec17 + (fRec25 + fTemp13)))))) - (fRec12[1] + (fRec20[1] + (fRec28[1] + (fRec36[1] + (fRec13 + (fRec21 + fTemp14)))))));
+ fRec9[0] = ((fRec12[1] + (fRec20[1] + (fRec32[1] + (fRec40[1] + (fRec13 + (fRec21 + fTemp13)))))) - (fRec16[1] + (fRec24[1] + (fRec28[1] + (fRec36[1] + (fRec17 + (fRec25 + fTemp14)))))));
+ float fTemp15 = (fRec41 + fRec29);
+ float fTemp16 = (fRec37 + fRec33);
+ fRec10[0] = ((fRec12[1] + (fRec24[1] + (fRec28[1] + (fRec40[1] + (fRec13 + (fRec25 + fTemp15)))))) - (fRec16[1] + (fRec20[1] + (fRec32[1] + (fRec36[1] + (fRec17 + (fRec21 + fTemp16)))))));
+ fRec11[0] = ((fRec16[1] + (fRec20[1] + (fRec28[1] + (fRec40[1] + (fRec17 + (fRec21 + fTemp15)))))) - (fRec12[1] + (fRec24[1] + (fRec32[1] + (fRec36[1] + (fRec13 + (fRec25 + fTemp16)))))));
+ float fTemp17 = (0.370000005f * (fRec5[0] + fRec6[0]));
+ float fTemp18 = (fSlow89 * fRec3[1]);
+ fRec3[0] = (fTemp17 - (fTemp18 + (fSlow9 * fRec3[2])));
+ float fTemp19 = (fSlow9 * fRec3[0]);
+ float fTemp20 = (0.5f * ((fTemp19 + (fRec3[2] + (fTemp17 + fTemp18))) + (fSlow7 * ((fTemp19 + (fTemp18 + fRec3[2])) - fTemp17))));
+ float fTemp21 = (fSlow90 * fRec2[1]);
+ fRec2[0] = (fTemp20 - (fTemp21 + (fSlow5 * fRec2[2])));
+ float fTemp22 = (fSlow5 * fRec2[0]);
+ float fTemp23 = (fTemp0 * (1.0f - fRec1[0]));
+ float fTemp24 = (0.370000005f * (fRec5[0] - fRec6[0]));
+ float fTemp25 = (fSlow89 * fRec45[1]);
+ fRec45[0] = (fTemp24 - (fTemp25 + (fSlow9 * fRec45[2])));
+ float fTemp26 = (fSlow9 * fRec45[0]);
+ float fTemp27 = (0.5f * ((fTemp26 + (fRec45[2] + (fTemp24 + fTemp25))) + (fSlow7 * ((fTemp26 + (fTemp25 + fRec45[2])) - fTemp24))));
+ float fTemp28 = (fSlow90 * fRec44[1]);
+ fRec44[0] = (fTemp27 - (fTemp28 + (fSlow5 * fRec44[2])));
+ float fTemp29 = (fSlow5 * fRec44[0]);
+ output0[i] = FAUSTFLOAT((fRec0[0] * (((0.5f * (fRec1[0] * ((fTemp22 + (fRec2[2] + (fTemp20 + fTemp21))) + (fSlow3 * ((fTemp22 + (fTemp21 + fRec2[2])) - fTemp20))))) + fTemp23) + (fTemp23 + (0.5f * (fRec1[0] * ((fTemp29 + (fRec44[2] + (fTemp27 + fTemp28))) + (fSlow3 * ((fTemp29 + (fTemp28 + fRec44[2])) - fTemp27)))))))));
+ IOTA = (IOTA + 1);
+ fRec0[1] = fRec0[0];
+ fRec1[1] = fRec1[0];
+ fRec15[1] = fRec15[0];
+ fRec14[1] = fRec14[0];
+ fRec12[1] = fRec12[0];
+ fRec19[1] = fRec19[0];
+ fRec18[1] = fRec18[0];
+ fRec16[1] = fRec16[0];
+ fRec23[1] = fRec23[0];
+ fRec22[1] = fRec22[0];
+ fRec20[1] = fRec20[0];
+ fRec27[1] = fRec27[0];
+ fRec26[1] = fRec26[0];
+ fRec24[1] = fRec24[0];
+ fRec31[1] = fRec31[0];
+ fRec30[1] = fRec30[0];
+ fRec28[1] = fRec28[0];
+ fRec35[1] = fRec35[0];
+ fRec34[1] = fRec34[0];
+ fRec32[1] = fRec32[0];
+ fRec39[1] = fRec39[0];
+ fRec38[1] = fRec38[0];
+ fRec36[1] = fRec36[0];
+ fRec43[1] = fRec43[0];
+ fRec42[1] = fRec42[0];
+ fRec40[1] = fRec40[0];
+ fRec4[2] = fRec4[1];
+ fRec4[1] = fRec4[0];
+ fRec5[2] = fRec5[1];
+ fRec5[1] = fRec5[0];
+ fRec6[2] = fRec6[1];
+ fRec6[1] = fRec6[0];
+ fRec7[2] = fRec7[1];
+ fRec7[1] = fRec7[0];
+ fRec8[2] = fRec8[1];
+ fRec8[1] = fRec8[0];
+ fRec9[2] = fRec9[1];
+ fRec9[1] = fRec9[0];
+ fRec10[2] = fRec10[1];
+ fRec10[1] = fRec10[0];
+ fRec11[2] = fRec11[1];
+ fRec11[1] = fRec11[0];
+ fRec3[2] = fRec3[1];
+ fRec3[1] = fRec3[0];
+ fRec2[2] = fRec2[1];
+ fRec2[1] = fRec2[0];
+ fRec45[2] = fRec45[1];
+ fRec45[1] = fRec45[0];
+ fRec44[2] = fRec44[1];
+ fRec44[1] = fRec44[0];
+ }
+ }
+
+};
+
+#endif