Merged in rcoaxil/love-patches/minor (pull request #75)

EFX implemented

Approved-by: Bart van Strien
Approved-by: Alex Szpakowski

--HG--
branch : minor
This commit is contained in:
Bart van Strien
2017-02-11 19:04:53 +00:00
21 changed files with 2248 additions and 153 deletions
+44 -1
View File
@@ -28,6 +28,7 @@
#include "common/Module.h"
#include "common/StringMap.h"
#include "Source.h"
#include "Effect.h"
#include "RecordingDevice.h"
namespace love
@@ -188,7 +189,8 @@ public:
virtual void setDopplerScale(float scale) = 0;
virtual float getDopplerScale() const = 0;
//virtual void setMeter(float scale) = 0;
//virtual float getMeter() const = 0;
/**
* @return Reference to a vector of pointers to recording devices. May be empty.
**/
@@ -206,6 +208,47 @@ public:
*/
virtual void setDistanceModel(DistanceModel distanceModel) = 0;
/**
* Sets scene EFX effect.
* @param slot Slot to put effect into.
* @param fxparams Effect description table.
* @return true if successful, false otherwise.
*/
virtual bool setSceneEffect(int slot, std::map<Effect::Parameter, float> &params) = 0;
/**
* Removes scene EFX effect.
* @param slot Effect slot to clear.
* @return true if successful, false otherwise.
*/
virtual bool setSceneEffect(int slot) = 0;
/**
* Gets scene EFX effect.
* @param slot Slot from which to get effect.
* @param fxparams Effect description table.
* @return true if effect was present, false otherwise.
*/
virtual bool getSceneEffect(int slot, std::map<Effect::Parameter, float> &params) = 0;
/**
* Gets maximum number of scene EFX effects.
* @return number of effects.
*/
virtual int getMaxSceneEffects() const = 0;
/**
* Gets maximum number of source EFX effects.
* @return number of effects.
*/
virtual int getMaxSourceEffects() const = 0;
/**
* Gets EFX (or analog) availability.
* @return true if supported.
*/
virtual bool isEFXsupported() const = 0;
private:
static StringMap<DistanceModel, DISTANCE_MAX_ENUM>::Entry distanceModelEntries[];
+390
View File
@@ -0,0 +1,390 @@
/**
* Copyright (c) 2006-2016 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#include "Effect.h"
namespace love
{
namespace audio
{
Effect::Effect()
{
}
Effect::~Effect()
{
}
Effect::Type Effect::getType() const
{
return type;
}
bool Effect::getConstant(const char *in, Type &out)
{
return types.find(in, out);
}
bool Effect::getConstant(Type in, const char *&out)
{
return types.find(in, out);
}
/*
bool Effect::getConstant(const char *in, Phoneme &out)
{
return phonemes.find(in, out);
}
bool Effect::getConstant(Phoneme in, const char *&out)
{
return phonemes.find(in, out);
}
*/
bool Effect::getConstant(const char *in, Waveform &out)
{
return waveforms.find(in, out);
}
bool Effect::getConstant(Waveform in, const char *&out)
{
return waveforms.find(in, out);
}
/*
bool Effect::getConstant(const char *in, Direction &out)
{
return directions.find(in, out);
}
bool Effect::getConstant(Direction in, const char *&out)
{
return directions.find(in, out);
}
*/
bool Effect::getConstant(const char *in, Parameter &out, Type t)
{
return parameterNames[t].find(in, out);
}
bool Effect::getConstant(Parameter in, const char *&out, Type t)
{
return parameterNames[t].find(in, out);
}
Effect::ParameterType Effect::getParameterType(Effect::Parameter in)
{
return parameterTypes[in];
}
StringMap<Effect::Type, Effect::TYPE_MAX_ENUM>::Entry Effect::typeEntries[] =
{
{"reverb", Effect::TYPE_REVERB},
{"chorus", Effect::TYPE_CHORUS},
{"distortion", Effect::TYPE_DISTORTION},
{"echo", Effect::TYPE_ECHO},
{"flanger", Effect::TYPE_FLANGER},
//{"frequencyshifter", Effect::TYPE_FREQSHIFTER},
//{"vocalmorpher", Effect::TYPE_MORPHER},
//{"pitchshifter", Effect::TYPE_PITCHSHIFTER},
{"ringmodulator", Effect::TYPE_MODULATOR},
//{"autowah", Effect::TYPE_AUTOWAH},
{"compressor", Effect::TYPE_COMPRESSOR},
{"equalizer", Effect::TYPE_EQUALIZER},
};
StringMap<Effect::Type, Effect::TYPE_MAX_ENUM> Effect::types(Effect::typeEntries, sizeof(Effect::typeEntries));
StringMap<Effect::Waveform, Effect::WAVE_MAX_ENUM>::Entry Effect::waveformEntries[] =
{
{"sine", Effect::WAVE_SINE},
{"triangle", Effect::WAVE_TRIANGLE},
{"sawtooth", Effect::WAVE_SAWTOOTH},
{"square", Effect::WAVE_SQUARE},
};
StringMap<Effect::Waveform, Effect::WAVE_MAX_ENUM> Effect::waveforms(Effect::waveformEntries, sizeof(Effect::waveformEntries));
/*
StringMap<Effect::Direction, Effect::DIR_MAX_ENUM>::Entry Effect::directionEntries[] =
{
{"up", Effect::DIR_UP},
{"down", Effect::DIR_DOWN},
{"none", Effect::DIR_NONE},
};
StringMap<Effect::Direction, Effect::DIR_MAX_ENUM> Effect::directions(Effect::directionEntries, sizeof(Effect::directionEntries));
StringMap<Effect::Phoneme, Effect::PHONEME_MAX_ENUM>::Entry Effect::phonemeEntries[] =
{
{"a", Effect::PHONEME_A},
{"e", Effect::PHONEME_E},
{"i", Effect::PHONEME_I},
{"o", Effect::PHONEME_O},
{"u", Effect::PHONEME_U},
{"aa", Effect::PHONEME_AA},
{"ae", Effect::PHONEME_AE},
{"ah", Effect::PHONEME_AH},
{"ao", Effect::PHONEME_AO},
{"eh", Effect::PHONEME_EH},
{"er", Effect::PHONEME_ER},
{"ih", Effect::PHONEME_IH},
{"iy", Effect::PHONEME_IY},
{"uh", Effect::PHONEME_UH},
{"uw", Effect::PHONEME_UW},
{"b", Effect::PHONEME_B},
{"d", Effect::PHONEME_D},
{"f", Effect::PHONEME_F},
{"g", Effect::PHONEME_G},
{"j", Effect::PHONEME_J},
{"k", Effect::PHONEME_K},
{"l", Effect::PHONEME_L},
{"m", Effect::PHONEME_M},
{"n", Effect::PHONEME_N},
{"p", Effect::PHONEME_P},
{"r", Effect::PHONEME_R},
{"s", Effect::PHONEME_S},
{"t", Effect::PHONEME_T},
{"v", Effect::PHONEME_V},
{"z", Effect::PHONEME_Z},
};
StringMap<Effect::Phoneme, Effect::PHONEME_MAX_ENUM> Effect::phonemes(Effect::phonemeEntries, sizeof(Effect::phonemeEntries));
*/
#define StringMap LazierAndSlowerButEasilyArrayableStringMap
std::vector<StringMap<Effect::Parameter>::Entry> Effect::basicParameters =
{
{"type", Effect::EFFECT_TYPE},
{"volume", Effect::EFFECT_VOLUME}
};
std::vector<StringMap<Effect::Parameter>::Entry> Effect::reverbParameters =
{
{"gain", Effect::REVERB_GAIN},
{"highgain", Effect::REVERB_HFGAIN},
{"density", Effect::REVERB_DENSITY},
{"diffusion", Effect::REVERB_DIFFUSION},
{"decaytime", Effect::REVERB_DECAY},
{"decayhighratio", Effect::REVERB_HFDECAY},
{"earlygain", Effect::REVERB_EARLYGAIN},
{"earlydelay", Effect::REVERB_EARLYDELAY},
{"lategain", Effect::REVERB_LATEGAIN},
{"latedelay", Effect::REVERB_LATEDELAY},
{"roomrolloff", Effect::REVERB_ROLLOFF},
{"airabsorption", Effect::REVERB_AIRHFGAIN},
{"highlimit", Effect::REVERB_HFLIMITER}
};
std::vector<StringMap<Effect::Parameter>::Entry> Effect::chorusParameters =
{
{"waveform", Effect::CHORUS_WAVEFORM},
{"phase", Effect::CHORUS_PHASE},
{"rate", Effect::CHORUS_RATE},
{"depth", Effect::CHORUS_DEPTH},
{"feedback", Effect::CHORUS_FEEDBACK},
{"delay", Effect::CHORUS_DELAY}
};
std::vector<StringMap<Effect::Parameter>::Entry> Effect::distortionParameters =
{
{"gain", Effect::DISTORTION_GAIN},
{"edge", Effect::DISTORTION_EDGE},
{"lowcut", Effect::DISTORTION_LOWCUT},
{"center", Effect::DISTORTION_EQCENTER},
{"bandwidth", Effect::DISTORTION_EQBAND}
};
std::vector<StringMap<Effect::Parameter>::Entry> Effect::echoParameters =
{
{"delay", Effect::ECHO_DELAY},
{"tapdelay", Effect::ECHO_LRDELAY},
{"damping", Effect::ECHO_DAMPING},
{"feedback", Effect::ECHO_FEEDBACK},
{"spread", Effect::ECHO_SPREAD}
};
std::vector<StringMap<Effect::Parameter>::Entry> Effect::flangerParameters =
{
{"waveform", Effect::FLANGER_WAVEFORM},
{"phase", Effect::FLANGER_PHASE},
{"rate", Effect::FLANGER_RATE},
{"depth", Effect::FLANGER_DEPTH},
{"feedback", Effect::FLANGER_FEEDBACK},
{"delay", Effect::FLANGER_DELAY}
};
/*
std::vector<StringMap<Effect::Parameter>::Entry> Effect::freqshifterParameters =
{
{"frequency", Effect::FREQSHIFTER_FREQ},
{"leftdirection", Effect::FREQSHIFTER_LEFTDIR},
{"rightdirection", Effect::FREQSHIFTER_RIGHTDIR}
};
std::vector<StringMap<Effect::Parameter>::Entry> Effect::morpherParameters =
{
{"waveform", Effect::MORPHER_WAVEFORM},
{"rate", Effect::MORPHER_RATE},
{"phonemea", Effect::MORPHER_PHONEMEA},
{"phonemeb", Effect::MORPHER_PHONEMEB},
{"tunea", Effect::MORPHER_COARSEA},
{"tuneb", Effect::MORPHER_COARSEB}
}
;
std::vector<StringMap<Effect::Parameter>::Entry> Effect::pitchshifterParameters =
{
{"pitch", Effect::PITCHSHIFTER_PITCH}
};
*/
std::vector<StringMap<Effect::Parameter>::Entry> Effect::modulatorParameters =
{
{"waveform", Effect::MODULATOR_WAVEFORM},
{"frequency", Effect::MODULATOR_FREQ},
{"highcut", Effect::MODULATOR_HIGHCUT}
};
/*
std::vector<StringMap<Effect::Parameter>::Entry> Effect::autowahParameters =
{
{"attack", Effect::AUTOWAH_ATTACK},
{"release", Effect::AUTOWAH_RELEASE},
{"resonance", Effect::AUTOWAH_RESONANCE},
{"peakgain", Effect::AUTOWAH_PEAKGAIN}
};
*/
std::vector<StringMap<Effect::Parameter>::Entry> Effect::compressorParameters =
{
{"enable", Effect::COMPRESSOR_ENABLE}
};
std::vector<StringMap<Effect::Parameter>::Entry> Effect::equalizerParameters =
{
{"lowgain", Effect::EQUALIZER_LOWGAIN},
{"lowcut", Effect::EQUALIZER_LOWCUT},
{"lowmidgain", Effect::EQUALIZER_MID1GAIN},
{"lowmidfrequency", Effect::EQUALIZER_MID1FREQ},
{"lowmidbandwidth", Effect::EQUALIZER_MID1BAND},
{"highmidgain", Effect::EQUALIZER_MID2GAIN},
{"highmidfrequency", Effect::EQUALIZER_MID2FREQ},
{"highmidbandwidth", Effect::EQUALIZER_MID2BAND},
{"highgain", Effect::EQUALIZER_HIGHGAIN},
{"highcut", Effect::EQUALIZER_HIGHCUT}
};
std::map<Effect::Type, StringMap<Effect::Parameter>> Effect::parameterNames =
{
{Effect::TYPE_BASIC, Effect::basicParameters},
{Effect::TYPE_REVERB, Effect::reverbParameters},
{Effect::TYPE_CHORUS, Effect::chorusParameters},
{Effect::TYPE_DISTORTION, Effect::distortionParameters},
{Effect::TYPE_ECHO, Effect::echoParameters},
{Effect::TYPE_FLANGER, Effect::flangerParameters},
//{Effect::TYPE_FREQSHIFTER, Effect::freqshifterParameters},
//{Effect::TYPE_MORPHER, Effect::morpherbParameters},
//{Effect::TYPE_PITCHSHIFTER, Effect::pitchshifterParameters},
{Effect::TYPE_MODULATOR, Effect::modulatorParameters},
//{Effect::TYPE_AUTOWAH, Effect::autowahParameters},
{Effect::TYPE_COMPRESSOR, Effect::compressorParameters},
{Effect::TYPE_EQUALIZER, Effect::equalizerParameters}
};
#undef StringMap
std::map<Effect::Parameter, Effect::ParameterType> Effect::parameterTypes =
{
{Effect::EFFECT_TYPE, Effect::PARAM_TYPE},
{Effect::EFFECT_VOLUME, Effect::PARAM_FLOAT},
{Effect::REVERB_GAIN, Effect::PARAM_FLOAT},
{Effect::REVERB_HFGAIN, Effect::PARAM_FLOAT},
{Effect::REVERB_DENSITY, Effect::PARAM_FLOAT},
{Effect::REVERB_DIFFUSION, Effect::PARAM_FLOAT},
{Effect::REVERB_DECAY, Effect::PARAM_FLOAT},
{Effect::REVERB_HFDECAY, Effect::PARAM_FLOAT},
{Effect::REVERB_EARLYGAIN, Effect::PARAM_FLOAT},
{Effect::REVERB_EARLYDELAY, Effect::PARAM_FLOAT},
{Effect::REVERB_LATEGAIN, Effect::PARAM_FLOAT},
{Effect::REVERB_LATEDELAY, Effect::PARAM_FLOAT},
{Effect::REVERB_ROLLOFF, Effect::PARAM_FLOAT},
{Effect::REVERB_AIRHFGAIN, Effect::PARAM_FLOAT},
{Effect::REVERB_HFLIMITER, Effect::PARAM_BOOL},
{Effect::CHORUS_WAVEFORM, Effect::PARAM_WAVEFORM},
{Effect::CHORUS_PHASE, Effect::PARAM_FLOAT},
{Effect::CHORUS_RATE, Effect::PARAM_FLOAT},
{Effect::CHORUS_DEPTH, Effect::PARAM_FLOAT},
{Effect::CHORUS_FEEDBACK, Effect::PARAM_FLOAT},
{Effect::CHORUS_DELAY, Effect::PARAM_FLOAT},
{Effect::DISTORTION_GAIN, Effect::PARAM_FLOAT},
{Effect::DISTORTION_EDGE, Effect::PARAM_FLOAT},
{Effect::DISTORTION_LOWCUT, Effect::PARAM_FLOAT},
{Effect::DISTORTION_EQCENTER, Effect::PARAM_FLOAT},
{Effect::DISTORTION_EQBAND, Effect::PARAM_FLOAT},
{Effect::ECHO_DELAY, Effect::PARAM_FLOAT},
{Effect::ECHO_LRDELAY, Effect::PARAM_FLOAT},
{Effect::ECHO_DAMPING, Effect::PARAM_FLOAT},
{Effect::ECHO_FEEDBACK, Effect::PARAM_FLOAT},
{Effect::ECHO_SPREAD, Effect::PARAM_FLOAT},
{Effect::FLANGER_WAVEFORM, Effect::PARAM_WAVEFORM},
{Effect::FLANGER_PHASE, Effect::PARAM_FLOAT},
{Effect::FLANGER_RATE, Effect::PARAM_FLOAT},
{Effect::FLANGER_DEPTH, Effect::PARAM_FLOAT},
{Effect::FLANGER_FEEDBACK, Effect::PARAM_FLOAT},
{Effect::FLANGER_DELAY, Effect::PARAM_FLOAT},
/*
{Effect::FREQSHIFTER_FREQ, Effect::PARAM_FLOAT},
{Effect::FREQSHIFTER_LEFTDIR, Effect::PARAM_DIRECTION},
{Effect::FREQSHIFTER_RIGHTDIR, Effect::PARAM_DIRECTION},
{Effect::MORPHER_WAVEFORM, Effect::PARAM_WAVEFORM},
{Effect::MORPHER_RATE, Effect::PARAM_FLOAT},
{Effect::MORPHER_PHONEMEA, Effect::PARAM_PHONEME},
{Effect::MORPHER_PHONEMEB, Effect::PARAM_PHONEME},
{Effect::MORPHER_TUNEA, Effect::PARAM_FLOAT},
{Effect::MORPHER_TUNEB, Effect::PARAM_FLOAT},
{Effect::PITCHSHIFTER_PITCH, Effect::PARAM_FLOAT},
*/
{Effect::MODULATOR_WAVEFORM, Effect::PARAM_WAVEFORM},
{Effect::MODULATOR_FREQ, Effect::PARAM_FLOAT},
{Effect::MODULATOR_HIGHCUT, Effect::PARAM_FLOAT},
/*
{Effect::AUTOWAH_ATTACK, Effect::PARAM_FLOAT},
{Effect::AUTOWAH_RELEASE, Effect::PARAM_FLOAT},
{Effect::AUTOWAH_RESONANCE, Effect::PARAM_FLOAT},
{Effect::AUTOWAH_PEAKGAIN, Effect::PARAM_FLOAT},
*/
{Effect::COMPRESSOR_ENABLE, Effect::PARAM_BOOL},
{Effect::EQUALIZER_LOWGAIN, Effect::PARAM_FLOAT},
{Effect::EQUALIZER_LOWCUT, Effect::PARAM_FLOAT},
{Effect::EQUALIZER_MID1GAIN, Effect::PARAM_FLOAT},
{Effect::EQUALIZER_MID1FREQ, Effect::PARAM_FLOAT},
{Effect::EQUALIZER_MID1BAND, Effect::PARAM_FLOAT},
{Effect::EQUALIZER_MID2GAIN, Effect::PARAM_FLOAT},
{Effect::EQUALIZER_MID2FREQ, Effect::PARAM_FLOAT},
{Effect::EQUALIZER_MID2BAND, Effect::PARAM_FLOAT},
{Effect::EQUALIZER_HIGHGAIN, Effect::PARAM_FLOAT},
{Effect::EQUALIZER_HIGHCUT, Effect::PARAM_FLOAT}
};
} //audio
} //love
+296
View File
@@ -0,0 +1,296 @@
/**
* Copyright (c) 2006-2016 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#ifndef LOVE_AUDIO_EFFECTS_H
#define LOVE_AUDIO_EFFECTS_H
#include "common/Object.h"
#include "common/StringMap.h"
#include <map>
#include <vector>
template<typename T>
class LazierAndSlowerButEasilyArrayableStringMap
{
public:
struct Entry
{
const char *key;
T value;
};
LazierAndSlowerButEasilyArrayableStringMap()
{
}
LazierAndSlowerButEasilyArrayableStringMap(const std::vector<Entry> &entries)
{
for (auto entry : entries)
{
forward[entry.key] = entry.value;
reverse[entry.value] = entry.key;
}
}
bool find(const char *key, T &t)
{
if (forward.find(key) == forward.end())
return false;
t = forward[key];
return true;
}
bool find(T key, const char *&str)
{
if (reverse.find(key) == reverse.end())
return false;
str = reverse[key];
return true;
}
private:
std::map<std::string, T> forward;
std::map<T, const char*> reverse;
};
namespace love
{
namespace audio
{
class Effect
{
public:
enum Type
{
TYPE_BASIC, //not a real type
TYPE_REVERB,
TYPE_CHORUS,
TYPE_DISTORTION,
TYPE_ECHO,
TYPE_FLANGER,
//TYPE_FREQSHIFTER,
//TYPE_MORPHER,
//TYPE_PITCHSHIFTER,
TYPE_MODULATOR,
//TYPE_AUTOWAH,
TYPE_COMPRESSOR,
TYPE_EQUALIZER,
TYPE_MAX_ENUM
};
enum Parameter
{
EFFECT_TYPE,
EFFECT_VOLUME,
REVERB_GAIN,
REVERB_HFGAIN,
REVERB_DENSITY,
REVERB_DIFFUSION,
REVERB_DECAY,
REVERB_HFDECAY,
REVERB_EARLYGAIN,
REVERB_EARLYDELAY,
REVERB_LATEGAIN,
REVERB_LATEDELAY,
REVERB_ROLLOFF,
REVERB_AIRHFGAIN,
REVERB_HFLIMITER,
CHORUS_WAVEFORM,
CHORUS_PHASE,
CHORUS_RATE,
CHORUS_DEPTH,
CHORUS_FEEDBACK,
CHORUS_DELAY,
DISTORTION_GAIN,
DISTORTION_EDGE,
DISTORTION_LOWCUT,
DISTORTION_EQCENTER,
DISTORTION_EQBAND,
ECHO_DELAY,
ECHO_LRDELAY,
ECHO_DAMPING,
ECHO_FEEDBACK,
ECHO_SPREAD,
FLANGER_WAVEFORM,
FLANGER_PHASE,
FLANGER_RATE,
FLANGER_DEPTH,
FLANGER_FEEDBACK,
FLANGER_DELAY,
/*
FREQSHIFTER_FREQ,
FREQSHIFTER_LEFTDIR,
FREQSHIFTER_RIGHTDIR,
MORPHER_WAVEFORM,
MORPHER_RATE,
MORPHER_PHONEMEA,
MORPHER_PHONEMEB,
MORPHER_TUNEA,
MORPHER_TUNEB,
PITCHSHIFTER_PITCH,
*/
MODULATOR_WAVEFORM,
MODULATOR_FREQ,
MODULATOR_HIGHCUT,
/*
AUTOWAH_ATTACK,
AUTOWAH_RELEASE,
AUTOWAH_RESONANCE,
AUTOWAH_PEAKGAIN,
*/
COMPRESSOR_ENABLE,
EQUALIZER_LOWGAIN,
EQUALIZER_LOWCUT,
EQUALIZER_MID1GAIN,
EQUALIZER_MID1FREQ,
EQUALIZER_MID1BAND,
EQUALIZER_MID2GAIN,
EQUALIZER_MID2FREQ,
EQUALIZER_MID2BAND,
EQUALIZER_HIGHGAIN,
EQUALIZER_HIGHCUT,
EFFECT_MAX_ENUM
};
enum ParameterType
{
PARAM_TYPE,
PARAM_FLOAT,
PARAM_BOOL,
PARAM_WAVEFORM,
//PARAM_DIRECTION,
//PARAM_PHONEME,
PARAM_MAX_ENUM
};
enum Waveform
{
WAVE_SINE,
WAVE_TRIANGLE,
WAVE_SAWTOOTH,
WAVE_SQUARE,
WAVE_MAX_ENUM
};
/*
enum Direction
{
DIR_NONE,
DIR_UP,
DIR_DOWN,
DIR_MAX_ENUM
};
enum Phoneme
{
PHONEME_A,
PHONEME_E,
PHONEME_I,
PHONEME_O,
PHONEME_U,
PHONEME_AA,
PHONEME_AE,
PHONEME_AH,
PHONEME_AO,
PHONEME_EH,
PHONEME_ER,
PHONEME_IH,
PHONEME_IY,
PHONEME_UH,
PHONEME_UW,
PHONEME_B,
PHONEME_D,
PHONEME_F,
PHONEME_G,
PHONEME_J,
PHONEME_K,
PHONEME_L,
PHONEME_M,
PHONEME_N,
PHONEME_P,
PHONEME_R,
PHONEME_S,
PHONEME_T,
PHONEME_V,
PHONEME_Z,
PHONEME_MAX_ENUM
};
*/
Effect();
virtual ~Effect();
Type getType() const;
static bool getConstant(const char *in, Type &out);
static bool getConstant(Type in, const char *&out);
static bool getConstant(const char *in, Waveform &out);
static bool getConstant(Waveform in, const char *&out);
//static bool getConstant(const char *in, Direction &out);
//static bool getConstant(Direction in, const char *&out);
//static bool getConstant(const char *in, Phoneme &out);
//static bool getConstant(Phoneme in, const char *&out);
static bool getConstant(const char *in, Parameter &out, Type t);
static bool getConstant(Parameter in, const char *&out, Type t);
static ParameterType getParameterType(Parameter in);
protected:
Type type;
private:
static StringMap<Type, TYPE_MAX_ENUM>::Entry typeEntries[];
static StringMap<Type, TYPE_MAX_ENUM> types;
static StringMap<Waveform, WAVE_MAX_ENUM>::Entry waveformEntries[];
static StringMap<Waveform, WAVE_MAX_ENUM> waveforms;
//static StringMap<Direction, DIR_MAX_ENUM>::Entry directionEntries[];
//static StringMap<Direction, DIR_MAX_ENUM> directions;
//static StringMap<Phoneme, PHONEME_MAX_ENUM>::Entry phonemeEntries[];
//static StringMap<Phoneme, PHONEME_MAX_ENUM> phonemes;
#define StringMap LazierAndSlowerButEasilyArrayableStringMap
static std::vector<StringMap<Effect::Parameter>::Entry> basicParameters;
static std::vector<StringMap<Effect::Parameter>::Entry> reverbParameters;
static std::vector<StringMap<Effect::Parameter>::Entry> chorusParameters;
static std::vector<StringMap<Effect::Parameter>::Entry> distortionParameters;
static std::vector<StringMap<Effect::Parameter>::Entry> echoParameters;
static std::vector<StringMap<Effect::Parameter>::Entry> flangerParameters;
//static std::vector<StringMap<Effect::Parameter>::Entry> freqshifterParameters;
//static std::vector<StringMap<Effect::Parameter>::Entry> morpherParameters;
//static std::vector<StringMap<Effect::Parameter>::Entry> pitchshifterParameters;
static std::vector<StringMap<Effect::Parameter>::Entry> modulatorParameters;
//static std::vector<StringMap<Effect::Parameter>::Entry> autowahParameters;
static std::vector<StringMap<Effect::Parameter>::Entry> compressorParameters;
static std::vector<StringMap<Effect::Parameter>::Entry> equalizerParameters;
static std::map<Type, StringMap<Parameter>> parameterNames;
#undef StringMap
static std::map<Parameter, ParameterType> parameterTypes;
};
} //audio
} //love
#endif //LOVE_AUDIO_EFFECTS_H
+46 -9
View File
@@ -48,14 +48,19 @@ bool Filter::getConstant(Type in, const char *&out)
return types.find(in, out);
}
int Filter::getParameterCount(Type in)
bool Filter::getConstant(const char *in, Parameter &out, Type t)
{
return parameterCount[in];
return parameterNames[t].find(in, out);
}
int Filter::getParameterCount()
bool Filter::getConstant(Parameter in, const char *&out, Type t)
{
return parameterCount[TYPE_MAX_ENUM];
return parameterNames[t].find(in, out);
}
Filter::ParameterType Filter::getParameterType(Parameter in)
{
return parameterTypes[in];
}
StringMap<Filter::Type, Filter::TYPE_MAX_ENUM>::Entry Filter::typeEntries[] =
@@ -67,12 +72,44 @@ StringMap<Filter::Type, Filter::TYPE_MAX_ENUM>::Entry Filter::typeEntries[] =
StringMap<Filter::Type, Filter::TYPE_MAX_ENUM> Filter::types(Filter::typeEntries, sizeof(Filter::typeEntries));
std::map<Filter::Type, int> Filter::parameterCount =
#define StringMap LazierAndSlowerButEasilyArrayableStringMap2
std::vector<StringMap<Filter::Parameter>::Entry> Filter::basicParameters =
{
{Filter::TYPE_LOWPASS, 2},
{Filter::TYPE_HIGHPASS, 2},
{Filter::TYPE_BANDPASS, 3},
{Filter::TYPE_MAX_ENUM, 3},
{"type", Filter::FILTER_TYPE},
{"volume", Filter::FILTER_VOLUME}
};
std::vector<StringMap<Filter::Parameter>::Entry> Filter::lowpassParameters =
{
{"highgain", Filter::FILTER_HIGHGAIN}
};
std::vector<StringMap<Filter::Parameter>::Entry> Filter::highpassParameters =
{
{"lowgain", Filter::FILTER_LOWGAIN}
};
std::vector<StringMap<Filter::Parameter>::Entry> Filter::bandpassParameters =
{
{"lowgain", Filter::FILTER_LOWGAIN},
{"highgain", Filter::FILTER_HIGHGAIN}
};
std::map<Filter::Type, StringMap<Filter::Parameter>> Filter::parameterNames =
{
{Filter::TYPE_BASIC, Filter::basicParameters},
{Filter::TYPE_LOWPASS, Filter::lowpassParameters},
{Filter::TYPE_HIGHPASS, Filter::highpassParameters},
{Filter::TYPE_BANDPASS, Filter::bandpassParameters},
};
#undef StringMap
std::map<Filter::Parameter, Filter::ParameterType> Filter::parameterTypes =
{
{Filter::FILTER_TYPE, Filter::PARAM_TYPE},
{Filter::FILTER_VOLUME, Filter::PARAM_FLOAT},
{Filter::FILTER_LOWGAIN, Filter::PARAM_FLOAT},
{Filter::FILTER_HIGHGAIN, Filter::PARAM_FLOAT}
};
} //audio
+73 -3
View File
@@ -25,6 +25,49 @@
#include "common/StringMap.h"
#include <map>
template<typename T>
class LazierAndSlowerButEasilyArrayableStringMap2
{
public:
struct Entry
{
const char *key;
T value;
};
LazierAndSlowerButEasilyArrayableStringMap2()
{
}
LazierAndSlowerButEasilyArrayableStringMap2(const std::vector<Entry> &entries)
{
for (auto entry : entries)
{
forward[entry.key] = entry.value;
reverse[entry.value] = entry.key;
}
}
bool find(const char *key, T &t)
{
if (forward.find(key) == forward.end())
return false;
t = forward[key];
return true;
}
bool find(T key, const char *&str)
{
if (reverse.find(key) == reverse.end())
return false;
str = reverse[key];
return true;
}
private:
std::map<std::string, T> forward;
std::map<T, const char*> reverse;
};
namespace love
{
namespace audio
@@ -35,20 +78,40 @@ class Filter
public:
enum Type
{
TYPE_BASIC,
TYPE_LOWPASS,
TYPE_HIGHPASS,
TYPE_BANDPASS,
TYPE_MAX_ENUM
};
enum Parameter
{
FILTER_TYPE,
FILTER_VOLUME,
FILTER_LOWGAIN,
FILTER_HIGHGAIN,
FILTER_MAX_ENUM
};
enum ParameterType
{
PARAM_TYPE,
PARAM_FLOAT,
PARAM_MAX_ENUM
};
Filter();
virtual ~Filter();
Type getType() const;
static bool getConstant(const char *in, Type &out);
static bool getConstant(Type in, const char *&out);
static int getParameterCount(Type in);
static int getParameterCount();
static bool getConstant(const char *in, Parameter &out, Type t);
static bool getConstant(Parameter in, const char *&out, Type t);
static ParameterType getParameterType(Parameter in);
protected:
Type type;
@@ -56,7 +119,14 @@ protected:
private:
static StringMap<Type, TYPE_MAX_ENUM>::Entry typeEntries[];
static StringMap<Type, TYPE_MAX_ENUM> types;
static std::map<Type, int> parameterCount;
#define StringMap LazierAndSlowerButEasilyArrayableStringMap2
static std::vector<StringMap<Filter::Parameter>::Entry> basicParameters;
static std::vector<StringMap<Filter::Parameter>::Entry> lowpassParameters;
static std::vector<StringMap<Filter::Parameter>::Entry> highpassParameters;
static std::vector<StringMap<Filter::Parameter>::Entry> bandpassParameters;
static std::map<Type, StringMap<Parameter>> parameterNames;
#undef StringMap
static std::map<Parameter, ParameterType> parameterTypes;
};
} //audio
+11 -4
View File
@@ -84,8 +84,8 @@ public:
virtual void setDirection(float *v) = 0;
virtual void getDirection(float *v) const = 0;
virtual void setCone(float innerAngle, float outerAngle, float outerVolume) = 0;
virtual void getCone(float &innerAngle, float &outerAngle, float &outerVolume) const = 0;
virtual void setCone(float innerAngle, float outerAngle, float outerVolume, float outerHighGain) = 0;
virtual void getCone(float &innerAngle, float &outerAngle, float &outerVolume, float &outerHighGain) const = 0;
virtual void setRelative(bool enable) = 0;
virtual bool isRelative() const = 0;
@@ -104,12 +104,19 @@ public:
virtual float getRolloffFactor() const = 0;
virtual void setMaxDistance(float distance) = 0;
virtual float getMaxDistance() const = 0;
virtual void setAirAbsorptionFactor(float factor) = 0;
virtual float getAirAbsorptionFactor() const = 0;
virtual int getChannels() const = 0;
virtual bool setFilter(Filter::Type type, std::vector<float> &params) = 0;
virtual bool setFilter(std::map<Filter::Parameter, float> &params) = 0;
virtual bool setFilter() = 0;
virtual bool getFilter(Filter::Type &type, std::vector<float> &params) = 0;
virtual bool getFilter(std::map<Filter::Parameter, float> &params) = 0;
virtual bool setSceneEffect(int slot, int effect) = 0;
virtual bool setSceneEffect(int slot, int effect, std::map<Filter::Parameter, float> &params) = 0;
virtual bool setSceneEffect(int slot) = 0;
virtual bool getSceneEffect(int slot, int &effect, std::map<Filter::Parameter, float> &params) = 0;
virtual int getFreeBufferCount() const = 0;
virtual bool queue(void *data, size_t length, int dataSampleRate, int dataBitDepth, int dataChannels) = 0;
+39
View File
@@ -143,7 +143,16 @@ float Audio::getDopplerScale() const
{
return 1.0f;
}
/*
void setMeter(float)
{
}
float getMeter() const
{
return 1.0f;
}
*/
const std::vector<love::audio::RecordingDevice*> &Audio::getRecordingDevices()
{
return capture;
@@ -159,6 +168,36 @@ void Audio::setDistanceModel(DistanceModel distanceModel)
this->distanceModel = distanceModel;
}
bool Audio::setSceneEffect(int, std::map<Effect::Parameter, float> &)
{
return false;
}
bool Audio::setSceneEffect(int)
{
return false;
}
bool Audio::getSceneEffect(int, std::map<Effect::Parameter, float> &)
{
return false;
}
int Audio::getMaxSceneEffects() const
{
return 0;
}
int Audio::getMaxSourceEffects() const
{
return 0;
}
bool Audio::isEFXsupported() const
{
return false;
}
} // null
} // audio
} // love
+9
View File
@@ -70,12 +70,21 @@ public:
void setDopplerScale(float scale);
float getDopplerScale() const;
//void setMeter(float scale);
//float getMeter() const;
const std::vector<love::audio::RecordingDevice*> &getRecordingDevices();
DistanceModel getDistanceModel() const;
void setDistanceModel(DistanceModel distanceModel);
bool setSceneEffect(int slot, std::map<Effect::Parameter, float> &params);
bool setSceneEffect(int slot);
bool getSceneEffect(int slot, std::map<Effect::Parameter, float> &params);
int getMaxSceneEffects() const;
int getMaxSourceEffects() const;
bool isEFXsupported() const;
private:
float volume;
DistanceModel distanceModel;
+36 -4
View File
@@ -128,18 +128,20 @@ void Source::getDirection(float *) const
{
}
void Source::setCone(float innerAngle, float outerAngle, float outerVolume)
void Source::setCone(float innerAngle, float outerAngle, float outerVolume, float outerHighGain)
{
coneInnerAngle = innerAngle;
coneOuterAngle = outerAngle;
coneOuterVolume = outerVolume;
coneOuterHighGain = outerHighGain;
}
void Source::getCone(float &innerAngle, float &outerAngle, float &outerVolume) const
void Source::getCone(float &innerAngle, float &outerAngle, float &outerVolume, float &outerHighGain) const
{
innerAngle = coneInnerAngle;
outerAngle = coneOuterAngle;
outerVolume = coneOuterVolume;
outerHighGain = coneOuterHighGain;
}
void Source::setRelative(bool enable)
@@ -212,6 +214,16 @@ float Source::getMaxDistance() const
return this->maxDistance;
}
void Source::setAirAbsorptionFactor(float factor)
{
absorptionFactor = factor;
}
float Source::getAirAbsorptionFactor() const
{
return absorptionFactor;
}
int Source::getChannels() const
{
return 2;
@@ -227,7 +239,7 @@ bool Source::queue(void *, size_t, int, int, int)
return false;
}
bool Source::setFilter(love::audio::Filter::Type, std::vector<float> &)
bool Source::setFilter(std::map<Filter::Parameter, float> &)
{
return false;
}
@@ -237,7 +249,27 @@ bool Source::setFilter()
return false;
}
bool Source::getFilter(love::audio::Filter::Type &, std::vector<float> &)
bool Source::getFilter(std::map<Filter::Parameter, float> &)
{
return false;
}
bool Source::setSceneEffect(int, int)
{
return false;
}
bool Source::setSceneEffect(int, int, std::map<Filter::Parameter, float> &)
{
return false;
}
bool Source::setSceneEffect(int)
{
return false;
}
bool Source::getSceneEffect(int, int &, std::map<Filter::Parameter, float> &)
{
return false;
}
+13 -4
View File
@@ -59,8 +59,8 @@ public:
virtual void getVelocity(float *v) const;
virtual void setDirection(float *v);
virtual void getDirection(float *v) const;
virtual void setCone(float innerAngle, float outerAngle, float outerVolume);
virtual void getCone(float &innerAngle, float &outerAngle, float &outerVolume) const;
virtual void setCone(float innerAngle, float outerAngle, float outerVolume, float outerHighGain);
virtual void getCone(float &innerAngle, float &outerAngle, float &outerVolume, float &outerHighGain) const;
virtual void setRelative(bool enable);
virtual bool isRelative() const;
void setLooping(bool looping);
@@ -75,14 +75,21 @@ public:
virtual float getRolloffFactor() const;
virtual void setMaxDistance(float distance);
virtual float getMaxDistance() const;
virtual void setAirAbsorptionFactor(float factor);
virtual float getAirAbsorptionFactor() const;
virtual int getChannels() const;
virtual int getFreeBufferCount() const;
virtual bool queue(void *data, size_t length, int dataSampleRate, int dataBitDepth, int dataChannels);
virtual bool setFilter(love::audio::Filter::Type type, std::vector<float> &params);
virtual bool setFilter(std::map<Filter::Parameter, float> &params);
virtual bool setFilter();
virtual bool getFilter(love::audio::Filter::Type &type, std::vector<float> &params);
virtual bool getFilter(std::map<Filter::Parameter, float> &params);
virtual bool setSceneEffect(int slot, int effect);
virtual bool setSceneEffect(int slot, int effect, std::map<Filter::Parameter, float> &params);
virtual bool setSceneEffect(int slot);
virtual bool getSceneEffect(int slot, int &effect, std::map<Filter::Parameter, float> &params);
private:
@@ -91,6 +98,7 @@ private:
float coneInnerAngle;
float coneOuterAngle;
float coneOuterVolume;
float coneOuterHighGain;
bool relative;
bool looping;
float minVolume;
@@ -98,6 +106,7 @@ private:
float referenceDistance;
float rolloffFactor;
float maxDistance;
float absorptionFactor;
}; // Source
+160 -8
View File
@@ -102,7 +102,13 @@ Audio::Audio()
if (device == nullptr)
throw love::Exception("Could not open device.");
context = alcCreateContext(device, nullptr);
#ifdef ALC_EXT_EFX
ALint attribs[4] = { ALC_MAX_AUXILIARY_SENDS, MAX_SOURCE_EFFECTS, 0, 0 };
#else
ALint *attribs = nullptr;
#endif
context = alcCreateContext(device, attribs);
if (context == nullptr)
throw love::Exception("Could not create context.");
@@ -110,20 +116,53 @@ Audio::Audio()
if (!alcMakeContextCurrent(context) || alcGetError(device) != ALC_NO_ERROR)
throw love::Exception("Could not make context current.");
#ifdef ALC_EXT_EFX
initializeEFX();
alcGetIntegerv(device, ALC_MAX_AUXILIARY_SENDS, 1, &MAX_SOURCE_EFFECTS);
alGetError();
if (alGenAuxiliaryEffectSlots)
{
for (int i = 0; i < MAX_SCENE_EFFECTS; i++)
{
ALuint slot;
alGenAuxiliaryEffectSlots(1, &slot);
if (alGetError() == AL_NO_ERROR)
{
effectIndex[slot] = effectSlots.size();
effectSlots.push_back(slot);
effects.push_back(nullptr);
}
else
{
MAX_SCENE_EFFECTS = i;
break;
}
}
}
else
MAX_SCENE_EFFECTS = MAX_SOURCE_EFFECTS = 0;
#else
MAX_SCENE_EFFECTS = MAX_SOURCE_EFFECTS = 0;
#endif
try
{
pool = new Pool();
}
catch (love::Exception &)
{
for (auto c : capture)
delete c;
#ifdef ALC_EXT_EFX
if (alDeleteAuxiliaryEffectSlots)
for (auto slot : effectSlots)
alDeleteAuxiliaryEffectSlots(1, &slot);
#endif
alcMakeContextCurrent(nullptr);
alcDestroyContext(context);
alcCloseDevice(device);
for (auto c : capture)
delete c;
throw;
}
@@ -138,15 +177,21 @@ Audio::~Audio()
delete poolThread;
delete pool;
for (auto c : capture)
delete c;
#ifdef ALC_EXT_EFX
for (auto e : effects)
if (e != nullptr)
delete e;
if (alDeleteAuxiliaryEffectSlots)
for (auto slot : effectSlots)
alDeleteAuxiliaryEffectSlots(1, &slot);
#endif
alcMakeContextCurrent(nullptr);
alcDestroyContext(context);
alcCloseDevice(device);
for (auto c : capture)
delete c;
}
const char *Audio::getName() const
{
return "love.audio.openal";
@@ -269,7 +314,23 @@ float Audio::getDopplerScale() const
{
return alGetFloat(AL_DOPPLER_FACTOR);
}
/*
void Audio::setMeter(float scale)
{
if (scale >= 0.0f)
{
metersPerUnit = scale;
#ifdef ALC_EXT_EFX
alListenerf(AL_METERS_PER_UNIT, scale);
#endif
}
}
float Audio::getMeter() const
{
return metersPerUnit;
}
*/
Audio::DistanceModel Audio::getDistanceModel() const
{
return distanceModel;
@@ -384,6 +445,97 @@ const std::vector<love::audio::RecordingDevice*> &Audio::getRecordingDevices()
return capture;
}
bool Audio::setSceneEffect(int slot, std::map<Effect::Parameter, float> &params)
{
if (slot < 0 || slot >= MAX_SCENE_EFFECTS)
return false;
if (!effects[slot])
effects[slot] = new Effect();
bool result = effects[slot]->setParams(params);
#ifdef ALC_EXT_EFX
if (alAuxiliaryEffectSloti)
{
if (result == true)
{
if (params.find(Effect::EFFECT_VOLUME) != params.end())
alAuxiliaryEffectSlotf(effectSlots[slot], AL_EFFECTSLOT_GAIN, params[Effect::EFFECT_VOLUME]);
alAuxiliaryEffectSloti(effectSlots[slot], AL_EFFECTSLOT_EFFECT, effects[slot]->getEffect());
}
else
alAuxiliaryEffectSloti(effectSlots[slot], AL_EFFECTSLOT_EFFECT, AL_EFFECT_NULL);
alGetError();
}
#endif
return result;
}
bool Audio::setSceneEffect(int slot)
{
if (slot < 0 || slot >= MAX_SCENE_EFFECTS)
return false;
if (effects[slot])
delete effects[slot];
effects[slot] = nullptr;
#ifdef ALC_EXT_EFX
if (alAuxiliaryEffectSloti)
alAuxiliaryEffectSloti(effectSlots[slot], AL_EFFECTSLOT_EFFECT, AL_EFFECT_NULL);
#endif
return true;
}
bool Audio::getSceneEffect(int slot, std::map<Effect::Parameter, float> &params)
{
if (slot < 0 || slot >= MAX_SCENE_EFFECTS)
return false;
if (!effects[slot])
return false;
params = effects[slot]->getParams();
return true;
}
int Audio::getMaxSceneEffects() const
{
return MAX_SCENE_EFFECTS;
}
int Audio::getMaxSourceEffects() const
{
return MAX_SOURCE_EFFECTS;
}
bool Audio::isEFXsupported() const
{
#ifdef ALC_EXT_EFX
return (alGenEffects != nullptr);
#else
return false;
#endif
}
ALuint Audio::getSceneEffectID(int slot)
{
if (slot < 0 || slot >= MAX_SCENE_EFFECTS)
return effectSlots[0];
return effectSlots[slot];
}
int Audio::getSceneEffectIndex(ALuint effect)
{
return effectIndex[effect];
}
#ifdef ALC_EXT_EFX
LPALGENEFFECTS alGenEffects = nullptr;
LPALDELETEEFFECTS alDeleteEffects = nullptr;
+21 -1
View File
@@ -35,6 +35,7 @@
#include "sound/SoundData.h"
#include "Source.h"
#include "Effect.h"
#include "Pool.h"
#include "thread/threads.h"
@@ -105,12 +106,24 @@ public:
void setDopplerScale(float scale);
float getDopplerScale() const;
//void setMeter(float scale);
//float getMeter() const;
const std::vector<love::audio::RecordingDevice*> &getRecordingDevices();
DistanceModel getDistanceModel() const;
void setDistanceModel(DistanceModel distanceModel);
bool setSceneEffect(int slot, std::map<Effect::Parameter, float> &params);
bool setSceneEffect(int slot);
bool getSceneEffect(int slot, std::map<Effect::Parameter, float> &params);
int getMaxSceneEffects() const;
int getMaxSourceEffects() const;
bool isEFXsupported() const;
ALuint getSceneEffectID(int slot);
int getSceneEffectIndex(ALuint effect);
private:
void initializeEFX();
// The OpenAL device.
@@ -122,6 +135,13 @@ private:
// The OpenAL context.
ALCcontext *context;
// The OpenAL effects
std::vector<Effect*> effects;
std::vector<ALuint> effectSlots;
std::map<ALuint, int> effectIndex;
int MAX_SCENE_EFFECTS = 16;
int MAX_SOURCE_EFFECTS = 16;
// The Pool.
Pool *pool;
@@ -148,7 +168,7 @@ private:
PoolThread *poolThread;
DistanceModel distanceModel;
//float metersPerUnit = 1.0;
}; // Audio
#ifdef ALC_EXT_EFX
+417
View File
@@ -0,0 +1,417 @@
/**
* Copyright (c) 2006-2016 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#include "Effect.h"
#include "common/Exception.h"
#include <cmath>
#include <iostream>
namespace love
{
namespace audio
{
namespace openal
{
//base class
Effect::Effect()
{
generateEffect();
}
Effect::Effect(const Effect &s)
: Effect()
{
setParams(s.getParams());
}
Effect::~Effect()
{
deleteEffect();
}
Effect *Effect::clone()
{
return new Effect(*this);
}
bool Effect::generateEffect()
{
#ifdef ALC_EXT_EFX
if (!alGenEffects)
return false;
if (effect != AL_EFFECT_NULL)
return true;
alGenEffects(1, &effect);
if (alGetError() != AL_NO_ERROR)
throw love::Exception("Failed to create sound Effect.");
return true;
#else
return false;
#endif
}
void Effect::deleteEffect()
{
#ifdef ALC_EXT_EFX
if (effect != AL_EFFECT_NULL)
alDeleteEffects(1, &effect);
#endif
effect = AL_EFFECT_NULL;
}
ALuint Effect::getEffect() const
{
return effect;
}
bool Effect::setParams(const std::map<Parameter, float> &params)
{
this->params = params;
type = static_cast<Type>(this->params[EFFECT_TYPE]);
if (!generateEffect())
return false;
#ifdef ALC_EXT_EFX
//parameter table without EFFECT_TYPE entry is illegal
switch (type)
{
case TYPE_REVERB:
alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_REVERB);
break;
case TYPE_CHORUS:
alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_CHORUS);
break;
case TYPE_DISTORTION:
alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_DISTORTION);
break;
case TYPE_ECHO:
alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_ECHO);
break;
case TYPE_FLANGER:
alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_FLANGER);
break;
/*
case TYPE_FREQSHIFTER:
alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_FREQUENCY_SHIFTER);
break;
case TYPE_MORPHER:
alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_VOCAL_MORPHER);
break;
case TYPE_PITCHSHIFTER:
alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_PITCH_SHIFTER);
break;
*/
case TYPE_MODULATOR:
alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_RING_MODULATOR);
break;
/*
case TYPE_AUTOWAH:
alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_AUTOWAH);
break;
*/
case TYPE_COMPRESSOR:
alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_COMPRESSOR);
break;
case TYPE_EQUALIZER:
alEffecti(effect, AL_EFFECT_TYPE, AL_EFFECT_EQUALIZER);
break;
case TYPE_BASIC:
case TYPE_MAX_ENUM:
break;
}
//failed to make effect specific type - not supported etc.
if (alGetError() != AL_NO_ERROR)
{
deleteEffect();
return false;
}
#define clampf(v,l,h) fmax(fmin((v),(h)),(l))
#define PARAMSTR(i,e,v) effect,AL_##e##_##v,clampf(getValue(i,AL_##e##_DEFAULT_##v),AL_##e##_MIN_##v,AL_##e##_MAX_##v)
switch (type)
{
case TYPE_REVERB:
{
alEffectf(PARAMSTR(REVERB_GAIN,REVERB,GAIN));
alEffectf(PARAMSTR(REVERB_HFGAIN,REVERB,GAINHF));
alEffectf(PARAMSTR(REVERB_DENSITY,REVERB,DENSITY));
alEffectf(PARAMSTR(REVERB_DIFFUSION,REVERB,DIFFUSION));
alEffectf(PARAMSTR(REVERB_DECAY,REVERB,DECAY_TIME));
alEffectf(PARAMSTR(REVERB_HFDECAY,REVERB,DECAY_HFRATIO));
alEffectf(PARAMSTR(REVERB_EARLYGAIN,REVERB,REFLECTIONS_GAIN));
alEffectf(PARAMSTR(REVERB_EARLYDELAY,REVERB,REFLECTIONS_DELAY));
alEffectf(PARAMSTR(REVERB_LATEGAIN,REVERB,LATE_REVERB_GAIN));
alEffectf(PARAMSTR(REVERB_LATEDELAY,REVERB,LATE_REVERB_DELAY));;
alEffectf(PARAMSTR(REVERB_ROLLOFF,REVERB,ROOM_ROLLOFF_FACTOR));
alEffectf(PARAMSTR(REVERB_AIRHFGAIN,REVERB,AIR_ABSORPTION_GAINHF));
alEffecti(effect, AL_REVERB_DECAY_HFLIMIT, getValue(REVERB_HFLIMITER, 0));
break;
}
case TYPE_CHORUS:
{
Waveform wave = static_cast<Waveform>(getValue(CHORUS_WAVEFORM, static_cast<int>(WAVE_MAX_ENUM)));
if (wave == WAVE_SINE)
alEffecti(effect, AL_CHORUS_WAVEFORM, AL_CHORUS_WAVEFORM_SINUSOID);
else if (wave == WAVE_TRIANGLE)
alEffecti(effect, AL_CHORUS_WAVEFORM, AL_CHORUS_WAVEFORM_TRIANGLE);
else
alEffecti(effect, AL_CHORUS_WAVEFORM, AL_CHORUS_DEFAULT_WAVEFORM);
alEffecti(PARAMSTR(CHORUS_PHASE,CHORUS,PHASE));
alEffectf(PARAMSTR(CHORUS_RATE,CHORUS,RATE));
alEffectf(PARAMSTR(CHORUS_DEPTH,CHORUS,DEPTH));
alEffectf(PARAMSTR(CHORUS_FEEDBACK,CHORUS,FEEDBACK));
alEffectf(PARAMSTR(CHORUS_DELAY,CHORUS,DELAY));
break;
}
case TYPE_DISTORTION:
alEffectf(PARAMSTR(DISTORTION_GAIN,DISTORTION,GAIN));
alEffectf(PARAMSTR(DISTORTION_EDGE,DISTORTION,EDGE));
alEffectf(PARAMSTR(DISTORTION_LOWCUT,DISTORTION,LOWPASS_CUTOFF));
alEffectf(PARAMSTR(DISTORTION_EQCENTER,DISTORTION,EQCENTER));
alEffectf(PARAMSTR(DISTORTION_EQBAND,DISTORTION,EQBANDWIDTH));
break;
case TYPE_ECHO:
alEffectf(PARAMSTR(ECHO_DELAY,ECHO,DELAY));
alEffectf(PARAMSTR(ECHO_LRDELAY,ECHO,LRDELAY));
alEffectf(PARAMSTR(ECHO_DAMPING,ECHO,DAMPING));
alEffectf(PARAMSTR(ECHO_FEEDBACK,ECHO,FEEDBACK));
alEffectf(PARAMSTR(ECHO_SPREAD,ECHO,SPREAD));
break;
case TYPE_FLANGER:
{
Waveform wave = static_cast<Waveform>(getValue(FLANGER_WAVEFORM, static_cast<int>(WAVE_MAX_ENUM)));
if (wave == WAVE_SINE)
alEffecti(effect, AL_FLANGER_WAVEFORM, AL_FLANGER_WAVEFORM_SINUSOID);
else if (wave == WAVE_TRIANGLE)
alEffecti(effect, AL_FLANGER_WAVEFORM, AL_FLANGER_WAVEFORM_TRIANGLE);
else
alEffecti(effect, AL_FLANGER_WAVEFORM, AL_FLANGER_DEFAULT_WAVEFORM);
alEffecti(PARAMSTR(FLANGER_PHASE,FLANGER,PHASE));
alEffectf(PARAMSTR(FLANGER_RATE,FLANGER,RATE));
alEffectf(PARAMSTR(FLANGER_DEPTH,FLANGER,DEPTH));
alEffectf(PARAMSTR(FLANGER_FEEDBACK,FLANGER,FEEDBACK));
alEffectf(PARAMSTR(FLANGER_DELAY,FLANGER,DELAY));
break;
}
/*
case TYPE_FREQSHIFTER:
{
alEffectf(PARAMSTR(FREQSHIFTER_FREQ,FREQUENCY_SHIFTER,FREQUENCY));
Direction dir = static_cast<Direction>(getValue(FREQSHIFTER_LEFTDIR, static_cast<int>(DIR_MAX_ENUM)));
if (dir == DIR_NONE)
alEffecti(effect, AL_FREQUENCY_SHIFTER_LEFT_DIRECTION, AL_FREQUENCY_SHIFTER_DIRECTION_OFF);
else if(dir == DIR_UP)
alEffecti(effect, AL_FREQUENCY_SHIFTER_LEFT_DIRECTION, AL_FREQUENCY_SHIFTER_DIRECTION_UP);
else if(dir == DIR_DOWN)
alEffecti(effect, AL_FREQUENCY_SHIFTER_LEFT_DIRECTION, AL_FREQUENCY_SHIFTER_DIRECTION_DOWN);
else
alEffecti(effect, AL_FREQUENCY_SHIFTER_LEFT_DIRECTION, AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION);
dir = static_cast<Direction>(getValue(FREQSHIFTER_RIGHTDIR, static_cast<int>(DIR_MAX_ENUM)));
if (dir == DIR_NONE)
alEffecti(effect, AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION, AL_FREQUENCY_SHIFTER_DIRECTION_OFF);
else if(dir == DIR_UP)
alEffecti(effect, AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION, AL_FREQUENCY_SHIFTER_DIRECTION_UP);
else if(dir == DIR_DOWN)
alEffecti(effect, AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION, AL_FREQUENCY_SHIFTER_DIRECTION_DOWN);
else
alEffecti(effect, AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION, AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION);
break;
}
case TYPE_MORPHER:
{
Waveform wave = static_cast<Waveform>(getValue(MORPHER_WAVEFORM, static_cast<int>(WAVE_MAX_ENUM)));
if (wave == WAVE_SINE)
alEffecti(effect, AL_VOCAL_MORPHER_WAVEFORM, AL_VOCAL_MORPHER_WAVEFORM_SINUSOID);
else if (wave == WAVE_TRIANGLE)
alEffecti(effect, AL_VOCAL_MORPHER_WAVEFORM, AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE);
else if (wave == WAVE_SAWTOOTH)
alEffecti(effect, AL_VOCAL_MORPHER_WAVEFORM, AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH);
else
alEffecti(effect, AL_VOCAL_MORPHER_WAVEFORM, AL_VOCAL_MORPHER_DEFAULT_WAVEFORM);
Phoneme phoneme = static_cast<Phoneme>(getValue(MORPHER_PHONEMEA, static_cast<int>(PHONEME_MAX_ENUM)));
if (phoneme == PHONEME_MAX_ENUM)
alEffecti(effect, AL_VOCAL_MORPHER_PHONEMEA, AL_VOCAL_MORPHER_DEFAULT_PHONEMEA);
else
alEffecti(effect, AL_VOCAL_MORPHER_PHONEMEA, phonemeMap[phoneme]);
phoneme = static_cast<Phoneme>(getValue(MORPHER_PHONEMEB, static_cast<int>(PHONEME_MAX_ENUM)));
if (phoneme == PHONEME_MAX_ENUM)
alEffecti(effect, AL_VOCAL_MORPHER_PHONEMEB, AL_VOCAL_MORPHER_DEFAULT_PHONEMEB);
else
alEffecti(effect, AL_VOCAL_MORPHER_PHONEMEB, phonemeMap[phoneme]);
alEffectf(PARAMSTR(MORPHER_RATE,VOCAL_MORPHER,RATE));
alEffecti(PARAMSTR(MORPHER_TUNEA,VOCAL_MORPHER,PHONEMEA_COARSE_TUNING));
alEffecti(PARAMSTR(MORPHER_TUNEB,VOCAL_MORPHER,PHONEMEB_COARSE_TUNING));
break;
}
case TYPE_PITCHSHIFTER:
{
float tune = getValue(PITCHSHIFTER_PITCH, (float)AL_PITCH_SHIFTER_DEFAULT_COARSE_TUNE + (float)(AL_PITCH_SHIFTER_DEFAULT_FINE_TUNE - 50) / 100.0 );
int coarse = (int)floor(tune);
int fine = (int)(fmod(tune, 1.0)*100.0);
if (fine > 50)
{
fine -= 100;
coarse += 1;
}
else if (fine < -50)
{
fine += 100;
coarse -= 1;
}
if (coarse > AL_PITCH_SHIFTER_MAX_COARSE_TUNE)
{
coarse = AL_PITCH_SHIFTER_MAX_COARSE_TUNE;
fine = AL_PITCH_SHIFTER_MAX_FINE_TUNE;
}
else if (coarse < AL_PITCH_SHIFTER_MIN_COARSE_TUNE)
{
coarse = AL_PITCH_SHIFTER_MIN_COARSE_TUNE;
fine = AL_PITCH_SHIFTER_MIN_FINE_TUNE;
}
alEffecti(effect, AL_PITCH_SHIFTER_COARSE_TUNE, coarse);
alEffecti(effect, AL_PITCH_SHIFTER_FINE_TUNE, fine);
break;
}
*/
case TYPE_MODULATOR:
{
Waveform wave = static_cast<Waveform>(getValue(MODULATOR_WAVEFORM,static_cast<int>(WAVE_MAX_ENUM)));
if (wave == WAVE_SINE)
alEffecti(effect, AL_RING_MODULATOR_WAVEFORM, AL_RING_MODULATOR_SINUSOID);
else if (wave == WAVE_SAWTOOTH)
alEffecti(effect, AL_RING_MODULATOR_WAVEFORM, AL_RING_MODULATOR_SAWTOOTH);
else if (wave == WAVE_SQUARE)
alEffecti(effect, AL_RING_MODULATOR_WAVEFORM, AL_RING_MODULATOR_SQUARE);
else
alEffecti(effect, AL_RING_MODULATOR_WAVEFORM, AL_RING_MODULATOR_DEFAULT_WAVEFORM);
alEffectf(PARAMSTR(MODULATOR_FREQ,RING_MODULATOR,FREQUENCY));
alEffectf(PARAMSTR(MODULATOR_HIGHCUT,RING_MODULATOR,HIGHPASS_CUTOFF));
break;
}
/*
case TYPE_AUTOWAH:
alEffectf(PARAMSTR(AUTOWAH_ATTACK,AUTOWAH,ATTACK_TIME));
alEffectf(PARAMSTR(AUTOWAH_RELEASE,AUTOWAH,RELEASE_TIME));
alEffectf(PARAMSTR(AUTOWAH_RESONANCE,AUTOWAH,RESONANCE));
alEffectf(PARAMSTR(AUTOWAH_PEAKGAIN,AUTOWAH,PEAK_GAIN));
break;
*/
case TYPE_COMPRESSOR:
alEffecti(effect, AL_COMPRESSOR_ONOFF, getValue(COMPRESSOR_ENABLE,static_cast<int>(AL_COMPRESSOR_DEFAULT_ONOFF)));
break;
case TYPE_EQUALIZER:
alEffectf(PARAMSTR(EQUALIZER_LOWGAIN,EQUALIZER,LOW_GAIN));
alEffectf(PARAMSTR(EQUALIZER_LOWCUT,EQUALIZER,LOW_CUTOFF));
alEffectf(PARAMSTR(EQUALIZER_MID1GAIN,EQUALIZER,MID1_GAIN));
alEffectf(PARAMSTR(EQUALIZER_MID1FREQ,EQUALIZER,MID1_CENTER));
alEffectf(PARAMSTR(EQUALIZER_MID1BAND,EQUALIZER,MID1_WIDTH));
alEffectf(PARAMSTR(EQUALIZER_MID2GAIN,EQUALIZER,MID2_GAIN));
alEffectf(PARAMSTR(EQUALIZER_MID2FREQ,EQUALIZER,MID2_CENTER));
alEffectf(PARAMSTR(EQUALIZER_MID2BAND,EQUALIZER,MID2_WIDTH));
alEffectf(PARAMSTR(EQUALIZER_HIGHGAIN,EQUALIZER,HIGH_GAIN));
alEffectf(PARAMSTR(EQUALIZER_HIGHCUT,EQUALIZER,HIGH_CUTOFF));
break;
case TYPE_BASIC:
case TYPE_MAX_ENUM:
break;
}
#undef PARAMSTR
#undef clampf
//alGetError();
return true;
#else
return false;
#endif //ALC_EXT_EFX
}
const std::map<Effect::Parameter, float> &Effect::getParams() const
{
return params;
}
float Effect::getValue(Parameter in, float def) const
{
return params.find(in) == params.end() ? def : params.at(in);
}
int Effect::getValue(Parameter in, int def) const
{
return params.find(in) == params.end() ? def : static_cast<int>(params.at(in));
}
/*
std::map<Effect::Phoneme, ALint> Effect::phonemeMap =
{
{Effect::PHONEME_A, AL_VOCAL_MORPHER_PHONEME_A},
{Effect::PHONEME_E, AL_VOCAL_MORPHER_PHONEME_E},
{Effect::PHONEME_I, AL_VOCAL_MORPHER_PHONEME_I},
{Effect::PHONEME_O, AL_VOCAL_MORPHER_PHONEME_O},
{Effect::PHONEME_U, AL_VOCAL_MORPHER_PHONEME_U},
{Effect::PHONEME_AA, AL_VOCAL_MORPHER_PHONEME_AA},
{Effect::PHONEME_AE, AL_VOCAL_MORPHER_PHONEME_AE},
{Effect::PHONEME_AH, AL_VOCAL_MORPHER_PHONEME_AH},
{Effect::PHONEME_AO, AL_VOCAL_MORPHER_PHONEME_AO},
{Effect::PHONEME_EH, AL_VOCAL_MORPHER_PHONEME_EH},
{Effect::PHONEME_ER, AL_VOCAL_MORPHER_PHONEME_ER},
{Effect::PHONEME_IH, AL_VOCAL_MORPHER_PHONEME_IH},
{Effect::PHONEME_IY, AL_VOCAL_MORPHER_PHONEME_IY},
{Effect::PHONEME_UH, AL_VOCAL_MORPHER_PHONEME_UH},
{Effect::PHONEME_UW, AL_VOCAL_MORPHER_PHONEME_UW},
{Effect::PHONEME_B, AL_VOCAL_MORPHER_PHONEME_B},
{Effect::PHONEME_D, AL_VOCAL_MORPHER_PHONEME_D},
{Effect::PHONEME_F, AL_VOCAL_MORPHER_PHONEME_F},
{Effect::PHONEME_G, AL_VOCAL_MORPHER_PHONEME_G},
{Effect::PHONEME_J, AL_VOCAL_MORPHER_PHONEME_J},
{Effect::PHONEME_K, AL_VOCAL_MORPHER_PHONEME_K},
{Effect::PHONEME_L, AL_VOCAL_MORPHER_PHONEME_L},
{Effect::PHONEME_M, AL_VOCAL_MORPHER_PHONEME_M},
{Effect::PHONEME_N, AL_VOCAL_MORPHER_PHONEME_N},
{Effect::PHONEME_P, AL_VOCAL_MORPHER_PHONEME_P},
{Effect::PHONEME_R, AL_VOCAL_MORPHER_PHONEME_R},
{Effect::PHONEME_S, AL_VOCAL_MORPHER_PHONEME_S},
{Effect::PHONEME_T, AL_VOCAL_MORPHER_PHONEME_T},
{Effect::PHONEME_V, AL_VOCAL_MORPHER_PHONEME_V},
{Effect::PHONEME_Z, AL_VOCAL_MORPHER_PHONEME_Z}
};
*/
} //openal
} //audio
} //love
+87
View File
@@ -0,0 +1,87 @@
/**
* Copyright (c) 2006-2016 LOVE Development Team
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
**/
#ifndef LOVE_AUDIO_OPENAL_EFFECTS_H
#define LOVE_AUDIO_OPENAL_EFFECTS_H
// OpenAL
#ifdef LOVE_APPLE_USE_FRAMEWORKS // Frameworks have different include paths.
#ifdef LOVE_IOS
#include <OpenAL/alc.h>
#include <OpenAL/al.h>
#else
#include <OpenAL-Soft/alc.h>
#include <OpenAL-Soft/al.h>
#include <OpenAL-Soft/alext.h>
#endif
#else
#include <AL/alc.h>
#include <AL/al.h>
#include <AL/alext.h>
#endif
#include <vector>
#include <map>
#include "audio/Effect.h"
#include "Audio.h"
#ifndef AL_EFFECT_NULL
#define AL_EFFECT_NULL (0)
#endif
#ifndef AL_EFFECTSLOT_NULL
#define AL_EFFECTSLOT_NULL (0)
#endif
namespace love
{
namespace audio
{
namespace openal
{
class Effect : public love::audio::Effect
{
public:
Effect();
Effect(const Effect &s);
virtual ~Effect();
virtual Effect *clone();
ALuint getEffect() const;
virtual bool setParams(const std::map<Parameter, float> &params);
virtual const std::map<Parameter, float> &getParams() const;
private:
bool generateEffect();
void deleteEffect();
float getValue(Parameter in, float def) const;
int getValue(Parameter in, int def) const;
ALuint effect = AL_EFFECT_NULL;
std::map<Parameter, float> params;
//static std::map<Phoneme, ALint> phonemeMap;
};
} //openal
} //audio
} //love
#endif //LOVE_AUDIO_OPENAL_EFFECTS_H
+65 -34
View File
@@ -21,6 +21,8 @@
#include "Filter.h"
#include "common/Exception.h"
#include <cmath>
namespace love
{
namespace audio
@@ -28,39 +30,21 @@ namespace audio
namespace openal
{
//clamp values silently to avoid randomly throwing errors due to implementation differences
float clampf(float val, float min, float max)
{
if (val < min) val = min;
else if (val > max) val = max;
return val;
}
//base class
Filter::Filter()
{
#ifdef ALC_EXT_EFX
if (!alGenFilters)
return;
alGenFilters(1, &filter);
if (alGetError() != AL_NO_ERROR)
throw love::Exception("Failed to create sound Filter.");
#endif
generateFilter();
}
Filter::Filter(const Filter &s)
: Filter()
{
setParams(s.getType(), s.getParams());
setParams(s.getParams());
}
Filter::~Filter()
{
#ifdef ALC_EXT_EFX
if (filter != AL_FILTER_NULL)
alDeleteFilters(1, &filter);
#endif
deleteFilter();
}
Filter *Filter::clone()
@@ -68,17 +52,45 @@ Filter *Filter::clone()
return new Filter(*this);
}
bool Filter::generateFilter()
{
#ifdef ALC_EXT_EFX
if (!alGenFilters)
return false;
if (filter != AL_FILTER_NULL)
return true;
alGenFilters(1, &filter);
if (alGetError() != AL_NO_ERROR)
throw love::Exception("Failed to create sound Filter.");
return true;
#else
return false;
#endif
}
void Filter::deleteFilter()
{
#ifdef ALC_EXT_EFX
if (filter != AL_FILTER_NULL)
alDeleteFilters(1, &filter);
#endif
filter = AL_FILTER_NULL;
}
ALuint Filter::getFilter() const
{
return filter;
}
bool Filter::setParams(Type type, const std::vector<float> &params)
bool Filter::setParams(const std::map<Parameter, float> &params)
{
this->type = type;
this->params = params;
type = static_cast<Type>(this->params[FILTER_TYPE]);
if (filter == AL_FILTER_NULL)
if (!generateFilter())
return false;
#ifdef ALC_EXT_EFX
@@ -93,6 +105,7 @@ bool Filter::setParams(Type type, const std::vector<float> &params)
case TYPE_BANDPASS:
alFilteri(filter, AL_FILTER_TYPE, AL_FILTER_BANDPASS);
break;
case TYPE_BASIC:
case TYPE_MAX_ENUM:
break;
}
@@ -100,38 +113,56 @@ bool Filter::setParams(Type type, const std::vector<float> &params)
//failed to make filter specific type - not supported etc.
if (alGetError() != AL_NO_ERROR)
{
filter = AL_FILTER_NULL;
deleteFilter();
return false;
}
#define clampf(v,l,h) fmax(fmin((v),(h)),(l))
#define PARAMSTR(i,e,v) filter,AL_##e##_##v,clampf(getValue(i,AL_##e##_DEFAULT_##v),AL_##e##_MIN_##v,AL_##e##_MAX_##v)
switch (type)
{
case TYPE_LOWPASS:
alFilterf(filter, AL_LOWPASS_GAIN, clampf(params[0], AL_LOWPASS_MIN_GAIN, AL_LOWPASS_MAX_GAIN));
alFilterf(filter, AL_LOWPASS_GAINHF, clampf(params[1], AL_LOWPASS_MIN_GAINHF, AL_LOWPASS_MAX_GAINHF));
alFilterf(PARAMSTR(FILTER_VOLUME,LOWPASS,GAIN));
alFilterf(PARAMSTR(FILTER_HIGHGAIN,LOWPASS,GAINHF));
break;
case TYPE_HIGHPASS:
alFilterf(filter, AL_HIGHPASS_GAIN, clampf(params[0], AL_HIGHPASS_MIN_GAIN, AL_HIGHPASS_MAX_GAIN));
alFilterf(filter, AL_HIGHPASS_GAINLF, clampf(params[1], AL_HIGHPASS_MIN_GAINLF, AL_HIGHPASS_MAX_GAINLF));
alFilterf(PARAMSTR(FILTER_VOLUME,HIGHPASS,GAIN));
alFilterf(PARAMSTR(FILTER_LOWGAIN,HIGHPASS,GAINLF));
break;
case TYPE_BANDPASS:
alFilterf(filter, AL_BANDPASS_GAIN, clampf(params[0], AL_BANDPASS_MIN_GAIN, AL_BANDPASS_MAX_GAIN));
alFilterf(filter, AL_BANDPASS_GAINLF, clampf(params[1], AL_BANDPASS_MIN_GAINLF, AL_BANDPASS_MAX_GAINLF));
alFilterf(filter, AL_BANDPASS_GAINHF, clampf(params[2], AL_BANDPASS_MIN_GAINHF, AL_BANDPASS_MAX_GAINHF));
alFilterf(PARAMSTR(FILTER_VOLUME,BANDPASS,GAIN));
alFilterf(PARAMSTR(FILTER_LOWGAIN,BANDPASS,GAINLF));
alFilterf(PARAMSTR(FILTER_HIGHGAIN,BANDPASS,GAINHF));
break;
case TYPE_BASIC:
case TYPE_MAX_ENUM:
break;
}
#endif
#undef clampf
#undef PARAMSTR
//alGetError();
return true;
#else
return false;
#endif
}
const std::vector<float> &Filter::getParams() const
const std::map<Filter::Parameter, float> &Filter::getParams() const
{
return params;
}
float Filter::getValue(Parameter in, float def) const
{
return params.find(in) == params.end() ? def : params.at(in);
}
int Filter::getValue(Parameter in, int def) const
{
return params.find(in) == params.end() ? def : static_cast<int>(params.at(in));
}
} //openal
} //audio
} //love
+7 -3
View File
@@ -63,12 +63,16 @@ public:
virtual ~Filter();
virtual Filter *clone();
ALuint getFilter() const;
virtual bool setParams(Type type, const std::vector<float> &params);
virtual const std::vector<float> &getParams() const;
virtual bool setParams(const std::map<Parameter, float> &params);
virtual const std::map<Parameter, float> &getParams() const;
private:
bool generateFilter();
void deleteFilter();
float getValue(Parameter in, float def) const;
int getValue(Parameter in, int def) const;
ALuint filter = AL_FILTER_NULL;
std::vector<float> params;
std::map<Parameter, float> params;
};
} //openal
+158 -19
View File
@@ -28,6 +28,8 @@
#include <iostream>
#include <algorithm>
#define audiomodule() (Module::getInstance<Audio>(Module::M_AUDIO))
namespace love
{
namespace audio
@@ -120,6 +122,8 @@ Source::Source(Pool *pool, love::sound::SoundData *soundData)
, sampleRate(soundData->getSampleRate())
, channels(soundData->getChannels())
, bitDepth(soundData->getBitDepth())
, sendfilters(audiomodule()->getMaxSourceEffects(), nullptr)
, sendtargets(audiomodule()->getMaxSourceEffects(), AL_EFFECTSLOT_NULL)
{
ALenum fmt = Audio::getFormat(soundData->getBitDepth(), soundData->getChannels());
if (fmt == AL_NONE)
@@ -142,6 +146,8 @@ Source::Source(Pool *pool, love::sound::Decoder *decoder)
, bitDepth(decoder->getBitDepth())
, decoder(decoder)
, unusedBufferTop(MAX_BUFFERS - 1)
, sendfilters(audiomodule()->getMaxSourceEffects(), nullptr)
, sendtargets(audiomodule()->getMaxSourceEffects(), AL_EFFECTSLOT_NULL)
{
if (Audio::getFormat(decoder->getBitDepth(), decoder->getChannels()) == AL_NONE)
throw InvalidFormatException(decoder->getChannels(), decoder->getBitDepth());
@@ -163,6 +169,8 @@ Source::Source(Pool *pool, int sampleRate, int bitDepth, int channels)
, sampleRate(sampleRate)
, channels(channels)
, bitDepth(bitDepth)
, sendfilters(audiomodule()->getMaxSourceEffects(), nullptr)
, sendtargets(audiomodule()->getMaxSourceEffects(), AL_EFFECTSLOT_NULL)
{
ALenum fmt = Audio::getFormat(bitDepth, channels);
if (fmt == AL_NONE)
@@ -202,6 +210,8 @@ Source::Source(const Source &s)
, decoder(nullptr)
, toLoop(0)
, unusedBufferTop(s.sourceType == TYPE_STREAM ? MAX_BUFFERS - 1 : -1)
, sendfilters(s.sendfilters)
, sendtargets(s.sendtargets)
{
if (sourceType == TYPE_STREAM)
{
@@ -214,8 +224,8 @@ Source::Source(const Source &s)
for (unsigned int i = 0; i < MAX_BUFFERS; i++)
unusedBuffers[i] = streamBuffers[i];
}
if (s.filter)
filter = s.filter->clone();
if (s.directfilter)
directfilter = s.directfilter->clone();
setFloatv(position, s.position);
setFloatv(velocity, s.velocity);
@@ -230,8 +240,12 @@ Source::~Source()
if (sourceType != TYPE_STATIC)
alDeleteBuffers(MAX_BUFFERS, streamBuffers);
if (filter)
delete filter;
if (directfilter)
delete directfilter;
for (auto sf : sendfilters)
if (sf != nullptr)
delete sf;
}
love::audio::Source *Source::clone()
@@ -619,7 +633,7 @@ void Source::getDirection(float *v) const
setFloatv(v, direction);
}
void Source::setCone(float innerAngle, float outerAngle, float outerVolume)
void Source::setCone(float innerAngle, float outerAngle, float outerVolume, float outerHighGain)
{
if (channels > 1)
throw SpatialSupportException();
@@ -627,16 +641,20 @@ void Source::setCone(float innerAngle, float outerAngle, float outerVolume)
cone.innerAngle = (int) LOVE_TODEG(innerAngle);
cone.outerAngle = (int) LOVE_TODEG(outerAngle);
cone.outerVolume = outerVolume;
cone.outerHighGain = outerHighGain;
if (valid)
{
alSourcei(source, AL_CONE_INNER_ANGLE, cone.innerAngle);
alSourcei(source, AL_CONE_OUTER_ANGLE, cone.outerAngle);
alSourcef(source, AL_CONE_OUTER_GAIN, cone.outerVolume);
#ifdef ALC_EXT_EFX
alSourcef(source, AL_CONE_OUTER_GAINHF, cone.outerHighGain);
#endif
}
}
void Source::getCone(float &innerAngle, float &outerAngle, float &outerVolume) const
void Source::getCone(float &innerAngle, float &outerAngle, float &outerVolume, float &outerHighGain) const
{
if (channels > 1)
throw SpatialSupportException();
@@ -644,6 +662,7 @@ void Source::getCone(float &innerAngle, float &outerAngle, float &outerVolume) c
innerAngle = LOVE_TORAD(cone.innerAngle);
outerAngle = LOVE_TORAD(cone.outerAngle);
outerVolume = cone.outerVolume;
outerHighGain = cone.outerHighGain;
}
void Source::setRelative(bool enable)
@@ -996,7 +1015,13 @@ void Source::reset()
alSourcei(source, AL_CONE_OUTER_ANGLE, cone.outerAngle);
alSourcef(source, AL_CONE_OUTER_GAIN, cone.outerVolume);
#ifdef ALC_EXT_EFX
alSourcei(source, AL_DIRECT_FILTER, filter ? filter->getFilter() : AL_FILTER_NULL);
alSourcef(source, AL_AIR_ABSORPTION_FACTOR, absorptionFactor);
alSourcef(source, AL_CONE_OUTER_GAINHF, cone.outerHighGain);
alSourcef(source, AL_ROOM_ROLLOFF_FACTOR, rolloffFactor); //reverb-specific rolloff
alSourcei(source, AL_DIRECT_FILTER, directfilter ? directfilter->getFilter() : AL_FILTER_NULL);
for (unsigned int i = 0; i < sendtargets.size(); i++)
alSource3i(source, AL_AUXILIARY_SEND_FILTER, sendtargets[i], i, sendfilters[i] ? sendfilters[i]->getFilter() : AL_FILTER_NULL);
//alGetError();
#endif
}
@@ -1199,21 +1224,48 @@ float Source::getMaxDistance() const
return maxDistance;
}
void Source::setAirAbsorptionFactor(float factor)
{
if (channels > 1)
throw SpatialSupportException();
absorptionFactor = factor;
#ifdef ALC_EXT_EFX
if (valid)
{
alSourcef(source, AL_AIR_ABSORPTION_FACTOR, absorptionFactor);
//alGetError();
}
#endif
}
float Source::getAirAbsorptionFactor() const
{
if (channels > 1)
throw SpatialSupportException();
return absorptionFactor;
}
int Source::getChannels() const
{
return channels;
}
bool Source::setFilter(love::audio::Filter::Type type, std::vector<float> &params)
bool Source::setFilter(std::map<Filter::Parameter, float> &params)
{
if (!filter)
filter = new Filter();
if (!directfilter)
directfilter = new Filter();
bool result = filter->setParams(type, params);
bool result = directfilter->setParams(params);
#ifdef ALC_EXT_EFX
if (valid)
alSourcei(source, AL_DIRECT_FILTER, filter->getFilter());
{
//in case of failure contains AL_FILTER_NULL, a valid non-filter
alSourcei(source, AL_DIRECT_FILTER, directfilter->getFilter());
//alGetError();
}
#endif
return result;
@@ -1221,26 +1273,113 @@ bool Source::setFilter(love::audio::Filter::Type type, std::vector<float> &param
bool Source::setFilter()
{
if (filter)
delete filter;
if (directfilter)
delete directfilter;
filter = nullptr;
directfilter = nullptr;
#ifdef ALC_EXT_EFX
if (valid)
{
alSourcei(source, AL_DIRECT_FILTER, AL_FILTER_NULL);
//alGetError();
}
#endif
return true;
}
bool Source::getFilter(love::audio::Filter::Type &type, std::vector<float> &params)
bool Source::getFilter(std::map<Filter::Parameter, float> &params)
{
if (!filter)
if (!directfilter)
return false;
type = filter->getType();
params = filter->getParams();
params = directfilter->getParams();
return true;
}
bool Source::setSceneEffect(int slot, int effect)
{
if (slot < 0 || slot >= (int)sendtargets.size())
return false;
sendtargets[slot] = dynamic_cast<Audio*>(audiomodule())->getSceneEffectID(effect);
if (sendfilters[slot])
delete sendfilters[slot];
sendfilters[slot] = nullptr;
#ifdef ALC_EXT_EFX
if (valid)
{
alSource3i(source, AL_AUXILIARY_SEND_FILTER, sendtargets[slot], slot, AL_FILTER_NULL);
//alGetError();
}
#endif
return true;
}
bool Source::setSceneEffect(int slot, int effect, std::map<Filter::Parameter, float> &params)
{
if (slot < 0 || slot >= (int)sendtargets.size())
return false;
sendtargets[slot] = dynamic_cast<Audio*>(audiomodule())->getSceneEffectID(effect);
if (!sendfilters[slot])
sendfilters[slot] = new Filter();
sendfilters[slot]->setParams(params);
#ifdef ALC_EXT_EFX
if (valid)
{
//in case of failure contains AL_FILTER_NULL, a valid non-filter
alSource3i(source, AL_AUXILIARY_SEND_FILTER, sendtargets[slot], slot, sendfilters[slot]->getFilter());
//alGetError();
}
#endif
return true;
}
bool Source::setSceneEffect(int slot)
{
if (slot < 0 || slot >= (int)sendtargets.size())
return false;
sendtargets[slot] = AL_EFFECTSLOT_NULL;
if (sendfilters[slot])
delete sendfilters[slot];
sendfilters[slot] = nullptr;
#ifdef ALC_EXT_EFX
if (valid)
{
alSource3i(source, AL_AUXILIARY_SEND_FILTER, AL_EFFECTSLOT_NULL, slot, AL_FILTER_NULL);
//alGetError();
}
#endif
return true;
}
bool Source::getSceneEffect(int slot, int &effect, std::map<Filter::Parameter, float> &params)
{
if (slot < 0 || slot >= (int)sendtargets.size())
return false;
if (sendtargets[slot] == AL_EFFECTSLOT_NULL)
return false;
effect = dynamic_cast<Audio*>(audiomodule())->getSceneEffectIndex(sendtargets[slot]);
if(sendfilters[slot])
params = sendfilters[slot]->getParams();
return true;
}
+16 -6
View File
@@ -126,8 +126,8 @@ public:
virtual void getVelocity(float *v) const;
virtual void setDirection(float *v);
virtual void getDirection(float *v) const;
virtual void setCone(float innerAngle, float outerAngle, float outerVolume);
virtual void getCone(float &innerAngle, float &outerAngle, float &outerVolume) const;
virtual void setCone(float innerAngle, float outerAngle, float outerVolume, float outerHighGain);
virtual void getCone(float &innerAngle, float &outerAngle, float &outerVolume, float &outerHighGain) const;
virtual void setRelative(bool enable);
virtual bool isRelative() const;
void setLooping(bool looping);
@@ -142,11 +142,18 @@ public:
virtual float getRolloffFactor() const;
virtual void setMaxDistance(float distance);
virtual float getMaxDistance() const;
virtual void setAirAbsorptionFactor(float factor);
virtual float getAirAbsorptionFactor() const;
virtual int getChannels() const;
virtual bool setFilter(love::audio::Filter::Type type, std::vector<float> &params);
virtual bool setFilter(std::map<Filter::Parameter, float> &params);
virtual bool setFilter();
virtual bool getFilter(love::audio::Filter::Type &type, std::vector<float> &params);
virtual bool getFilter(std::map<Filter::Parameter, float> &params);
virtual bool setSceneEffect(int slot, int effect);
virtual bool setSceneEffect(int slot, int effect, std::map<Filter::Parameter, float> &params);
virtual bool setSceneEffect(int slot);
virtual bool getSceneEffect(int slot, int &effect, std::map<Filter::Parameter, float> &params);
virtual int getFreeBufferCount() const;
virtual bool queue(void *data, size_t length, int dataSampleRate, int dataBitDepth, int dataChannels);
@@ -199,6 +206,7 @@ private:
float maxVolume = 1.0f;
float referenceDistance = 1.0f;
float rolloffFactor = 1.0f;
float absorptionFactor = 0.0f;
float maxDistance = MAX_ATTENUATION_DISTANCE;
struct Cone
@@ -206,6 +214,7 @@ private:
int innerAngle = 360; // degrees
int outerAngle = 360; // degrees
float outerVolume = 0.0f;
float outerHighGain = 1.0f;
} cone;
float offsetSamples = 0.0f;
@@ -221,8 +230,9 @@ private:
int unusedBufferTop = -1;
ALsizei bufferedBytes = 0;
Filter *filter = nullptr;
Filter *directfilter = nullptr;
std::vector<Filter*> sendfilters;
std::vector<ALint> sendtargets;
}; // Source
} // openal
+196
View File
@@ -28,6 +28,7 @@
// C++
#include <iostream>
#include <cmath>
namespace love
{
@@ -256,7 +257,19 @@ int w_getDopplerScale(lua_State *L)
lua_pushnumber(L, instance()->getDopplerScale());
return 1;
}
/*
int w_setMeter(lua_State *L)
{
instance()->setMeter(luax_checkfloat(L, 1));
return 0;
}
int w_getMeter(lua_State *L)
{
lua_pushnumber(L, instance()->getMeter());
return 1;
}
*/
int w_setDistanceModel(lua_State *L)
{
const char *modelStr = luaL_checkstring(L, 1);
@@ -292,6 +305,182 @@ int w_getRecordingDevices(lua_State *L)
return 1;
}
int w_setSceneEffect(lua_State *L)
{
int slot = luaL_checknumber(L, 1) - 1;
if (lua_gettop(L) == 1 || (lua_gettop(L) == 2 && lua_isnoneornil(L, 2)))
{
lua_pushboolean(L, instance()->setSceneEffect(slot));
return 1;
}
luaL_checktype(L, 2, LUA_TTABLE);
const char *paramstr = nullptr;
//find type (mandatory)
Effect::getConstant(Effect::EFFECT_TYPE, paramstr, Effect::TYPE_BASIC);
lua_pushstring(L, paramstr);
lua_rawget(L, 2);
if (lua_type(L, -1) == LUA_TNIL)
return luaL_error(L, "Effect type not specificed.");
Effect::Type type = Effect::TYPE_MAX_ENUM;
const char *typestr = luaL_checkstring(L, -1);
if (!Effect::getConstant(typestr, type))
return luaL_error(L, "Invalid Effect type: %s", typestr);
lua_pop(L, 1);
std::map<Effect::Parameter, float> params;
params[Effect::EFFECT_TYPE] = static_cast<int>(type);
// Iterate over the whole table, reading valid parameters and erroring on invalid ones
lua_pushnil(L);
while (lua_next(L, 2))
{
const char *keystr = luaL_checkstring(L, -2);
Effect::Parameter param;
if(Effect::getConstant(keystr, param, type) || Effect::getConstant(keystr, param, Effect::TYPE_BASIC))
{
#define luax_effecterror(l,t) luaL_error(l,"Bad parameter type for %s %s: " t " expected, got %s", typestr, keystr, lua_typename(L, -1))
switch(Effect::getParameterType(param))
{
case Effect::PARAM_FLOAT:
if (!lua_isnumber(L, -1))
return luax_effecterror(L, "number");
params[param] = lua_tonumber(L, -1);
break;
case Effect::PARAM_BOOL:
if (!lua_isboolean(L, -1))
return luax_effecterror(L, "boolean");
params[param] = lua_toboolean(L, -1) ? 1.0 : 0.0;
break;
case Effect::PARAM_WAVEFORM:
{
if (!lua_isstring(L, -1))
return luax_effecterror(L, "string");
paramstr = lua_tostring(L, -1);
Effect::Waveform waveform;
if (!Effect::getConstant(paramstr, waveform))
return luaL_error(L, "Invalid waveform type: %s", paramstr);
params[param] = static_cast<int>(waveform);
break;
}
/*
case Effect::PARAM_DIRECTION:
{
if (!lua_isstring(L, -1))
return luax_effecterror(L, "string");
paramstr = lua_tostring(L, -1);
Effect::Direction direction;
if (!Effect::getConstant(paramstr, direction))
return luaL_error(L, "Invalid direction type: %s", paramstr);
params[param] = static_cast<int>(direction);
break;
}
case Effect::PARAM_PHONEME:
{
if (!lua_isstring(L, -1))
return luax_effecterror(L, "string");
paramstr = lua_tostring(L, -1);
Effect::Phoneme phoneme;
if (!Effect::getConstant(basicstr, phoneme))
return luaL_error(L, "Invalid phoneme type: %s", paramstr);
params[param] = static_cast<int>(phoneme);
break;
}
*/
case Effect::PARAM_TYPE:
case Effect::PARAM_MAX_ENUM:
break;
}
#undef luax_effecterror
}
else
luaL_error(L, "Invalid '%s' Effect parameter: %s", typestr, keystr);
//remove the value (-1) from stack, keep the key (-2) to feed into lua_next
lua_pop(L, 1);
}
luax_catchexcept(L, [&]() { lua_pushboolean(L, instance()->setSceneEffect(slot, params)); });
return 1;
}
int w_getSceneEffect(lua_State *L)
{
int slot = luaL_checknumber(L, 1) - 1;
std::map<Effect::Parameter, float> params;
if (!instance()->getSceneEffect(slot, params))
return 0;
const char *keystr, *valstr;
Effect::Type type = static_cast<Effect::Type>((int)params[Effect::EFFECT_TYPE]);
lua_createtable(L, 0, params.size());
for (auto p : params)
{
if (!Effect::getConstant(p.first, keystr, type))
Effect::getConstant(p.first, keystr, Effect::TYPE_BASIC);
lua_pushstring(L, keystr);
switch (Effect::getParameterType(p.first))
{
case Effect::PARAM_FLOAT:
lua_pushnumber(L, p.second);
break;
case Effect::PARAM_BOOL:
lua_pushboolean(L, p.second > 0.5 ? true : false);
break;
case Effect::PARAM_WAVEFORM:
Effect::getConstant(static_cast<Effect::Waveform>((int)p.second), valstr);
lua_pushstring(L, valstr);
break;
/*
case Effect::PARAM_DIRECTION:
Effect::getConstant(static_cast<Effect::Direction>((int)p.second), valstr);
lua_pushstring(L, valstr);
break;
case Effect::PARAM_PHONEME:
Effect::getConstant(static_cast<Effect::Phoneme>((int)p.second), valstr);
lua_pushstring(L, valstr);
break;
*/
case Effect::PARAM_TYPE:
Effect::getConstant(static_cast<Effect::Type>((int)p.second), valstr);
lua_pushstring(L, valstr);
break;
case Effect::PARAM_MAX_ENUM:
break;
}
lua_rawset(L, -3);
}
return 1;
}
int w_getMaxSceneEffects(lua_State *L)
{
lua_pushnumber(L, instance()->getMaxSceneEffects());
return 1;
}
int w_getMaxSourceEffects(lua_State *L)
{
lua_pushnumber(L, instance()->getMaxSourceEffects());
return 1;
}
int w_isSceneEffectsSupported(lua_State *L)
{
lua_pushboolean(L, instance()->isEFXsupported());
return 1;
}
// List of functions to wrap.
static const luaL_Reg functions[] =
{
@@ -311,9 +500,16 @@ static const luaL_Reg functions[] =
{ "getVelocity", w_getVelocity },
{ "setDopplerScale", w_setDopplerScale },
{ "getDopplerScale", w_getDopplerScale },
//{ "setMeter", w_setMeter },
//{ "getMeter", w_setMeter },
{ "setDistanceModel", w_setDistanceModel },
{ "getDistanceModel", w_getDistanceModel },
{ "getRecordingDevices", w_getRecordingDevices },
{ "setEffect", w_setSceneEffect },
{ "getEffect", w_getSceneEffect },
{ "getMaxSceneEffects", w_getMaxSceneEffects },
{ "getMaxSourceEffects", w_getMaxSourceEffects },
{ "isEffectsSupported", w_isSceneEffectsSupported },
{ 0, 0 }
};
+160 -57
View File
@@ -23,6 +23,9 @@
#include "sound/SoundData.h"
#include "wrap_Source.h"
#include <cmath>
#include <iostream>
namespace love
{
namespace audio
@@ -212,19 +215,21 @@ int w_Source_setCone(lua_State *L)
float innerAngle = (float) luaL_checknumber(L, 2);
float outerAngle = (float) luaL_checknumber(L, 3);
float outerVolume = (float) luaL_optnumber(L, 4, 0.0);
luax_catchexcept(L, [&](){ t->setCone(innerAngle, outerAngle, outerVolume); });
float outerHighGain = (float) luaL_optnumber(L, 5, 1.0);
luax_catchexcept(L, [&](){ t->setCone(innerAngle, outerAngle, outerVolume, outerHighGain); });
return 0;
}
int w_Source_getCone(lua_State *L)
{
Source *t = luax_checksource(L, 1);
float innerAngle, outerAngle, outerVolume;
luax_catchexcept(L, [&](){ t->getCone(innerAngle, outerAngle, outerVolume); });
float innerAngle, outerAngle, outerVolume, outerHighGain;
luax_catchexcept(L, [&](){ t->getCone(innerAngle, outerAngle, outerVolume, outerHighGain); });
lua_pushnumber(L, innerAngle);
lua_pushnumber(L, outerAngle);
lua_pushnumber(L, outerVolume);
return 3;
lua_pushnumber(L, outerHighGain);
return 4;
}
int w_Source_setRelative(lua_State *L)
@@ -323,6 +328,16 @@ int w_Source_getRolloff(lua_State *L)
return 1;
}
int w_Source_setAirAbsorption(lua_State *L)
{
Source *t = luax_checksource(L, 1);
float factor = (float)luaL_checknumber(L, 2);
if (factor < 0.0f)
return luaL_error(L, "Invalid air absorption factor: %f. Must be > 0.", factor);
luax_catchexcept(L, [&](){ t->setAirAbsorptionFactor(factor); });
return 0;
}
int w_Source_getChannels(lua_State *L)
{
Source *t = luax_checksource(L, 1);
@@ -330,74 +345,160 @@ int w_Source_getChannels(lua_State *L)
return 1;
}
int setFilterReadFilter(lua_State *L, int idx, std::map<Filter::Parameter, float> &params)
{
if (lua_gettop(L) < idx || lua_isnoneornil(L, idx))
return 0;
luaL_checktype(L, idx, LUA_TTABLE);
const char *paramstr = nullptr;
Filter::getConstant(Filter::FILTER_TYPE, paramstr, Filter::TYPE_BASIC);
lua_pushstring(L, paramstr);
lua_rawget(L, idx);
if (lua_type(L, -1) == LUA_TNIL)
return luaL_error(L, "Filter type not specificed.");
Filter::Type type = Filter::TYPE_MAX_ENUM;
const char *typestr = luaL_checkstring(L, -1);
if (!Filter::getConstant(typestr, type))
return luaL_error(L, "Invalid Filter type: %s", typestr);
lua_pop(L, 1);
params[Filter::FILTER_TYPE] = static_cast<int>(type);
lua_pushnil(L);
while (lua_next(L, idx))
{
const char *keystr = luaL_checkstring(L, -2);
Filter::Parameter param;
if(Filter::getConstant(keystr, param, type) || Filter::getConstant(keystr, param, Filter::TYPE_BASIC))
{
#define luax_effecterror(l,t) luaL_error(l,"Bad parameter type for %s %s: " t " expected, got %s", typestr, keystr, lua_typename(L, -1))
switch(Filter::getParameterType(param))
{
case Filter::PARAM_FLOAT:
if (!lua_isnumber(L, -1))
return luax_effecterror(L, "number");
params[param] = lua_tonumber(L, -1);
break;
case Filter::PARAM_TYPE:
case Filter::PARAM_MAX_ENUM:
break;
}
#undef luax_effecterror
}
else
luaL_error(L, "Invalid '%s' Effect parameter: %s", typestr, keystr);
//remove the value (-1) from stack, keep the key (-2) to feed into lua_next
lua_pop(L, 1);
}
return 1;
}
void getFilterWriteFilter(lua_State *L, std::map<Filter::Parameter, float> &params)
{
const char *keystr, *valstr;
Filter::Type type = static_cast<Filter::Type>((int)params[Filter::FILTER_TYPE]);
lua_createtable(L, 0, params.size());
for (auto p : params)
{
if (!Filter::getConstant(p.first, keystr, type))
Filter::getConstant(p.first, keystr, Filter::TYPE_BASIC);
lua_pushstring(L, keystr);
switch (Filter::getParameterType(p.first))
{
case Filter::PARAM_FLOAT:
lua_pushnumber(L, p.second);
break;
case Filter::PARAM_TYPE:
Filter::getConstant(static_cast<Filter::Type>((int)p.second), valstr);
lua_pushstring(L, valstr);
break;
case Filter::PARAM_MAX_ENUM:
break;
}
lua_rawset(L, -3);
}
}
int w_Source_setFilter(lua_State *L)
{
Source *t = luax_checksource(L, 1);
Filter::Type type;
std::vector<float> params;
std::map<Filter::Parameter, float> params;
params.reserve(Filter::getParameterCount());
if (lua_gettop(L) == 1)
{
lua_pushboolean(L, t->setFilter());
return 1;
}
else if (lua_gettop(L) > 2)
{
const char *ftypestr = luaL_checkstring(L, 2);
if (!Filter::getConstant(ftypestr, type))
return luaL_error(L, "Invalid filter type: %s", ftypestr);
unsigned int count = Filter::getParameterCount(type);
for (unsigned int i = 0; i < count; i++)
params.push_back(luaL_checknumber(L, i + 3));
}
else if (lua_istable(L, 2))
{
if (lua_objlen(L, 2) == 0) //empty table also clears filter
{
lua_pushboolean(L, t->setFilter());
return 1;
}
lua_rawgeti(L, 2, 1);
const char *ftypestr = luaL_checkstring(L, -1);
if (!Filter::getConstant(ftypestr, type))
return luaL_error(L, "Invalid filter type: %s", ftypestr);
lua_pop(L, 1);
unsigned int count = Filter::getParameterCount(type);
for (unsigned int i = 0; i < count; i++)
{
lua_rawgeti(L, 2, i + 2);
params.push_back(luaL_checknumber(L, -1));
lua_pop(L, 1);
}
}
if (setFilterReadFilter(L, 2, params) == 1)
luax_catchexcept(L, [&]() { lua_pushboolean(L, t->setFilter(params)); });
else
return luax_typerror(L, 2, "filter description");
luax_catchexcept(L, [&]() { lua_pushboolean(L, t->setFilter()); });
luax_catchexcept(L, [&]() { lua_pushboolean(L, t->setFilter(type, params)); });
return 1;
}
int w_Source_getFilter(lua_State *L)
{
Source *t = luax_checksource(L, 1);
Filter::Type type;
std::vector<float> params;
if (!t->getFilter(type, params))
std::map<Filter::Parameter, float> params;
if (!t->getFilter(params))
return 0;
const char *str = nullptr;
Filter::getConstant(type, str);
lua_pushstring(L, str);
getFilterWriteFilter(L, params);
return 1;
}
for (unsigned int i = 0; i < params.size(); i++)
lua_pushnumber(L, params[i]);
int w_Source_setSceneEffect(lua_State *L)
{
Source *t = luax_checksource(L, 1);
return params.size() + 1;
int slot = luaL_checknumber(L, 2) - 1;
if (lua_gettop(L) == 2)
{
luax_catchexcept(L, [&]() { lua_pushboolean(L, t->setSceneEffect(slot)); });
return 1;
}
int effect = luaL_checknumber(L, 3) - 1;
if (lua_gettop(L) == 3)
{
luax_catchexcept(L, [&]() { lua_pushboolean(L, t->setSceneEffect(slot, effect)); });
return 1;
}
std::map<Filter::Parameter, float> params;
if (setFilterReadFilter(L, 4, params) == 1)
luax_catchexcept(L, [&]() { lua_pushboolean(L, t->setSceneEffect(slot, effect, params)); });
else
luax_catchexcept(L, [&]() { lua_pushboolean(L, t->setSceneEffect(slot, effect)); });
return 1;
}
int w_Source_getSceneEffect(lua_State *L)
{
Source *t = luax_checksource(L, 1);
int slot = luaL_checknumber(L, 2) - 1;
int effect;
std::map<Filter::Parameter, float> params;
if (!t->getSceneEffect(slot, effect, params))
return 0;
lua_pushnumber(L, effect + 1);
if (params.size() == 0)
return 1;
getFilterWriteFilter(L, params);
return 2;
}
int w_Source_getFreeBufferCount(lua_State *L)
@@ -505,13 +606,15 @@ static const luaL_Reg w_Source_functions[] =
{ "getVolumeLimits", w_Source_getVolumeLimits },
{ "setAttenuationDistances", w_Source_setAttenuationDistances },
{ "getAttenuationDistances", w_Source_getAttenuationDistances },
{ "setRolloff", w_Source_setRolloff},
{ "getRolloff", w_Source_getRolloff},
{ "setRolloff", w_Source_setRolloff },
{ "getRolloff", w_Source_getRolloff },
{ "getChannels", w_Source_getChannels },
{ "setFilter", w_Source_setFilter },
{ "getFilter", w_Source_getFilter },
{ "setEffect", w_Source_setSceneEffect },
{ "getEffect", w_Source_getSceneEffect },
{ "getFreeBufferCount", w_Source_getFreeBufferCount },
{ "queue", w_Source_queue },