mirror of
https://github.com/vsariola/sointu.git
synced 2025-06-04 01:28:45 -04:00
383 lines
10 KiB
C++
383 lines
10 KiB
C++
#include <stddef.h>
|
||
#include <string.h>
|
||
#include <stdio.h>
|
||
#include <math.h>
|
||
|
||
#include "AudioEffect.hpp"
|
||
#include "AEffEditor.hpp"
|
||
|
||
//-----------------------------------------------------------------------------
|
||
long dispatchEffectClass (AEffect *e, long opCode,
|
||
long index, long value, void *ptr, float opt)
|
||
{
|
||
AudioEffect *ae = (AudioEffect *)(e->object);
|
||
|
||
if(opCode == effClose)
|
||
{
|
||
ae->dispatcher(opCode, index, value, ptr, opt);
|
||
delete ae;
|
||
return 1;
|
||
}
|
||
|
||
return ae->dispatcher(opCode, index, value, ptr, opt);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
float getParameterClass(AEffect *e, long index)
|
||
{
|
||
AudioEffect *ae = (AudioEffect *)(e->object);
|
||
return ae->getParameter(index);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
void setParameterClass(AEffect *e, long index, float value)
|
||
{
|
||
AudioEffect *ae = (AudioEffect *)(e->object);
|
||
ae->setParameter(index, value);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
void processClass(AEffect *e, float **inputs, float **outputs, long sampleFrames)
|
||
{
|
||
AudioEffect *ae = (AudioEffect *)(e->object);
|
||
ae->process(inputs, outputs, sampleFrames);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
void processClassReplacing(AEffect *e, float **inputs, float **outputs, long sampleFrames)
|
||
{
|
||
AudioEffect *ae = (AudioEffect *)(e->object);
|
||
ae->processReplacing(inputs, outputs, sampleFrames);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
//-----------------------------------------------------------------------------
|
||
|
||
AudioEffect::AudioEffect(audioMasterCallback audioMaster, long numPrograms, long numParams)
|
||
{
|
||
this->audioMaster = audioMaster;
|
||
editor = 0;
|
||
this->numPrograms = numPrograms;
|
||
this->numParams = numParams;
|
||
curProgram = 0;
|
||
|
||
memset(&cEffect, 0, sizeof(cEffect));
|
||
cEffect.magic = kEffectMagic;
|
||
cEffect.dispatcher = dispatchEffectClass;
|
||
cEffect.process = processClass;
|
||
cEffect.setParameter = setParameterClass;
|
||
cEffect.getParameter = getParameterClass;
|
||
cEffect.numPrograms = numPrograms;
|
||
cEffect.numParams = numParams;
|
||
cEffect.numInputs = 1;
|
||
cEffect.numOutputs = 2;
|
||
cEffect.flags = 0;
|
||
cEffect.resvd1 = 0;
|
||
cEffect.resvd2 = 0;
|
||
cEffect.initialDelay = 0;
|
||
cEffect.realQualities = 0;
|
||
cEffect.offQualities = 0;
|
||
cEffect.ioRatio = 1.f;
|
||
cEffect.object = this;
|
||
cEffect.user = 0;
|
||
cEffect.uniqueID = 'NoEf'; // you must set this!
|
||
cEffect.version = 1;
|
||
cEffect.processReplacing = processClassReplacing;
|
||
|
||
sampleRate = 44100.f;
|
||
blockSize = 1024L;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
AudioEffect::~AudioEffect()
|
||
{
|
||
if(editor)
|
||
delete editor;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
long AudioEffect::dispatcher(long opCode, long index, long value, void *ptr, float opt)
|
||
{
|
||
long v = 0;
|
||
|
||
switch(opCode)
|
||
{
|
||
case effOpen: open(); break;
|
||
case effClose: close(); break;
|
||
case effSetProgram: if(value < numPrograms) setProgram(value); break;
|
||
case effGetProgram: v = getProgram(); break;
|
||
case effSetProgramName: setProgramName((char *)ptr); break;
|
||
case effGetProgramName: getProgramName((char *)ptr); break;
|
||
case effGetParamLabel: getParameterLabel(index, (char *)ptr); break;
|
||
case effGetParamDisplay: getParameterDisplay(index, (char *)ptr); break;
|
||
case effGetParamName: getParameterName(index, (char *)ptr); break;
|
||
|
||
case effSetSampleRate: setSampleRate(opt); break;
|
||
case effSetBlockSize: setBlockSize(value); break;
|
||
case effMainsChanged: if(!value) suspend(); else resume(); break;
|
||
case effGetVu: v = (long)(getVu() * 32767.); break;
|
||
|
||
// editor
|
||
|
||
case effEditGetRect: if(editor) v = editor->getRect((ERect **)ptr); break;
|
||
case effEditOpen: if(editor) v = editor->open(ptr); break;
|
||
case effEditClose: if(editor) editor->close(); break;
|
||
case effEditIdle: if(editor) editor->idle(); break;
|
||
|
||
#if MAC
|
||
case effEditDraw: if(editor) editor->draw((ERect *)ptr); break;
|
||
case effEditMouse: if(editor) v = editor->mouse(index, value); break;
|
||
case effEditKey: if(editor) v = editor->key(value); break;
|
||
case effEditTop: if(editor) editor->top(); break;
|
||
case effEditSleep: if(editor) editor->sleep(); break;
|
||
#endif
|
||
|
||
// new
|
||
|
||
case effIdentify: v = 'NvEf'; break;
|
||
case effGetChunk: v = getChunk((void**)ptr, index ? true : false); break;
|
||
case effSetChunk: v = setChunk(ptr, value, index ? true : false); break;
|
||
}
|
||
return v;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
long AudioEffect::getMasterVersion()
|
||
{
|
||
long version = 1;
|
||
if(audioMaster)
|
||
{
|
||
version = audioMaster(&cEffect, audioMasterVersion, 0, 0, 0, 0);
|
||
if(!version) // old
|
||
version = 1;
|
||
}
|
||
return version;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
long AudioEffect::getCurrentUniqueId()
|
||
{
|
||
long id = 0;
|
||
if(audioMaster)
|
||
id = audioMaster(&cEffect, audioMasterCurrentId, 0, 0, 0, 0);
|
||
return id;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
void AudioEffect::masterIdle()
|
||
{
|
||
if(audioMaster)
|
||
audioMaster(&cEffect, audioMasterIdle, 0, 0, 0, 0);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
bool AudioEffect::isInputConnected(long input)
|
||
{
|
||
long ret = 0;
|
||
if(audioMaster)
|
||
ret = audioMaster(&cEffect, audioMasterPinConnected, input, 0, 0, 0);
|
||
return ret ? false : true; // return value is 0 for true
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
bool AudioEffect::isOutputConnected(long output)
|
||
{
|
||
long ret = 0;
|
||
if(audioMaster)
|
||
ret = audioMaster(&cEffect, audioMasterPinConnected, output, 1, 0, 0);
|
||
return ret ? false : true; // return value is 0 for true
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// flags
|
||
|
||
//-----------------------------------------------------------------------------
|
||
void AudioEffect::hasVu(bool state)
|
||
{
|
||
if(state)
|
||
cEffect.flags |= effFlagsHasVu;
|
||
else
|
||
cEffect.flags &= ~effFlagsHasVu;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
void AudioEffect::hasClip(bool state)
|
||
{
|
||
if(state)
|
||
cEffect.flags |= effFlagsHasClip;
|
||
else
|
||
cEffect.flags &= ~effFlagsHasClip;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
void AudioEffect::canMono(bool state)
|
||
{
|
||
if(state)
|
||
cEffect.flags |= effFlagsCanMono;
|
||
else
|
||
cEffect.flags &= ~effFlagsCanMono;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
void AudioEffect::canProcessReplacing(bool state)
|
||
{
|
||
if(state)
|
||
cEffect.flags |= effFlagsCanReplacing;
|
||
else
|
||
cEffect.flags &= ~effFlagsCanReplacing;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
void AudioEffect::programsAreChunks(bool state)
|
||
{
|
||
if(state)
|
||
cEffect.flags |= effFlagsProgramChunks;
|
||
else
|
||
cEffect.flags &= ~effFlagsProgramChunks;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
void AudioEffect::setRealtimeQualities(long qualities)
|
||
{
|
||
cEffect.realQualities = qualities;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
void AudioEffect::setOfflineQualities(long qualities)
|
||
{
|
||
cEffect.offQualities = qualities;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
void AudioEffect::setInitialDelay(long delay)
|
||
{
|
||
cEffect.initialDelay = delay;
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
// string
|
||
|
||
//-----------------------------------------------------------------------------
|
||
void AudioEffect::dB2string(float value, char *text)
|
||
{
|
||
if(value <= 0)
|
||
#if MAC
|
||
strcpy(text, " -<2D> ");
|
||
#else
|
||
strcpy(text, " -oo ");
|
||
#endif
|
||
else
|
||
float2string((float)(20. * log10(value)), text);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
void AudioEffect::Hz2string(float samples, char *text)
|
||
{
|
||
float sampleRate = getSampleRate();
|
||
if(!samples)
|
||
float2string(0, text);
|
||
else
|
||
float2string(sampleRate / samples, text);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
void AudioEffect::ms2string(float samples, char *text)
|
||
{
|
||
float2string((float)(samples * 1000. / getSampleRate()), text);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
void AudioEffect::float2string(float value, char *text)
|
||
{
|
||
long c = 0, neg = 0;
|
||
char string[32];
|
||
char *s;
|
||
double v, integ, i10, mantissa, m10, ten = 10.;
|
||
|
||
v = (double)value;
|
||
if(v < 0)
|
||
{
|
||
neg = 1;
|
||
value = -value;
|
||
v = -v;
|
||
c++;
|
||
if(v > 9999999.)
|
||
{
|
||
strcpy(string, " Huge! ");
|
||
return;
|
||
}
|
||
}
|
||
else if(v > 99999999.)
|
||
{
|
||
strcpy(string, " Huge! ");
|
||
return;
|
||
}
|
||
|
||
s = string + 31;
|
||
*s-- = 0;
|
||
*s-- = '.';
|
||
c++;
|
||
|
||
integ = floor(v);
|
||
i10 = fmod(integ, ten);
|
||
*s-- = (long)i10 + '0';
|
||
integ /= ten;
|
||
c++;
|
||
while(integ >= 1. && c < 8)
|
||
{
|
||
i10 = fmod(integ, ten);
|
||
*s-- = (long)i10 + '0';
|
||
integ /= ten;
|
||
c++;
|
||
}
|
||
if(neg)
|
||
*s-- = '-';
|
||
strcpy(text, s + 1);
|
||
if(c >= 8)
|
||
return;
|
||
|
||
s = string + 31;
|
||
*s-- = 0;
|
||
mantissa = fmod(v, 1.);
|
||
mantissa *= pow(ten, (double)(8 - c));
|
||
while(c < 8)
|
||
{
|
||
if(mantissa <= 0)
|
||
*s-- = '0';
|
||
else
|
||
{
|
||
m10 = fmod(mantissa, ten);
|
||
*s-- = (long)m10 + '0';
|
||
mantissa /= 10.;
|
||
}
|
||
c++;
|
||
}
|
||
strcat(text, s + 1);
|
||
}
|
||
|
||
//-----------------------------------------------------------------------------
|
||
void AudioEffect::long2string(long value, char *text)
|
||
{
|
||
char string[32];
|
||
|
||
if(value >= 100000000)
|
||
{
|
||
strcpy(text, " Huge! ");
|
||
return;
|
||
}
|
||
sprintf(string, "%7d", value);
|
||
string[8] = 0;
|
||
strcpy(text, (char *)string);
|
||
}
|
||
|
||
|
||
//-----------------------------------------------------------------------------
|
||
//-----------------------------------------------------------------------------
|
||
void AudioEffect::setParameterAutomated(long index, float value)
|
||
{
|
||
setParameter(index, value);
|
||
if(audioMaster)
|
||
audioMaster(&cEffect, audioMasterAutomate, index, 0, 0, value); // value is in opt
|
||
}
|
||
|