From 0d3b041aa25cefb16b6ef2e5d0ad0a2f93986a92 Mon Sep 17 00:00:00 2001
From: Chris Robinson <chris.kcat@gmail.com>
Date: Mon, 21 Dec 2020 21:11:25 -0800
Subject: Avoid AL types and enums in the effect processors

---
 al/effects/chorus.cpp    |  66 ++++++++++++++------
 al/effects/echo.cpp      |   3 +
 al/effects/fshifter.cpp  |  44 +++++++++++---
 al/effects/modulator.cpp |  38 +++++++++---
 al/effects/vmorpher.cpp  | 154 +++++++++++++++++++++++++++++++++++++++--------
 5 files changed, 244 insertions(+), 61 deletions(-)

(limited to 'al/effects')

diff --git a/al/effects/chorus.cpp b/al/effects/chorus.cpp
index 2d983885..b2395283 100644
--- a/al/effects/chorus.cpp
+++ b/al/effects/chorus.cpp
@@ -4,25 +4,50 @@
 #include "AL/al.h"
 #include "AL/efx.h"
 
+#include "aloptional.h"
+#include "core/logging.h"
 #include "effects.h"
 #include "effects/base.h"
 
 
 namespace {
 
+static_assert(AL_CHORUS_WAVEFORM_SINUSOID == AL_FLANGER_WAVEFORM_SINUSOID, "Chorus/Flanger waveform value mismatch");
+static_assert(AL_CHORUS_WAVEFORM_TRIANGLE == AL_FLANGER_WAVEFORM_TRIANGLE, "Chorus/Flanger waveform value mismatch");
+
+inline al::optional<ChorusWaveform> WaveformFromEnum(ALenum type)
+{
+    switch(type)
+    {
+    case AL_CHORUS_WAVEFORM_SINUSOID: return al::make_optional(ChorusWaveform::Sinusoid);
+    case AL_CHORUS_WAVEFORM_TRIANGLE: return al::make_optional(ChorusWaveform::Triangle);
+    }
+    return al::nullopt;
+}
+inline ALenum EnumFromWaveform(ChorusWaveform type)
+{
+    switch(type)
+    {
+    case ChorusWaveform::Sinusoid: return AL_CHORUS_WAVEFORM_SINUSOID;
+    case ChorusWaveform::Triangle: return AL_CHORUS_WAVEFORM_TRIANGLE;
+    }
+    throw std::runtime_error{"Invalid chorus waveform: "+std::to_string(static_cast<int>(type))};
+}
+
 void Chorus_setParami(EffectProps *props, ALenum param, int val)
 {
     switch(param)
     {
     case AL_CHORUS_WAVEFORM:
-        if(!(val >= AL_CHORUS_MIN_WAVEFORM && val <= AL_CHORUS_MAX_WAVEFORM))
-            throw effect_exception{AL_INVALID_VALUE, "Invalid chorus waveform"};
-        props->Chorus.Waveform = val;
+        if(auto formopt = WaveformFromEnum(val))
+            props->Chorus.Waveform = *formopt;
+        else
+            throw effect_exception{AL_INVALID_VALUE, "Invalid chorus waveform: 0x%04x", val};
         break;
 
     case AL_CHORUS_PHASE:
         if(!(val >= AL_CHORUS_MIN_PHASE && val <= AL_CHORUS_MAX_PHASE))
-            throw effect_exception{AL_INVALID_VALUE, "Chorus phase out of range"};
+            throw effect_exception{AL_INVALID_VALUE, "Chorus phase out of range: %d", val};
         props->Chorus.Phase = val;
         break;
 
@@ -38,25 +63,25 @@ void Chorus_setParamf(EffectProps *props, ALenum param, float val)
     {
     case AL_CHORUS_RATE:
         if(!(val >= AL_CHORUS_MIN_RATE && val <= AL_CHORUS_MAX_RATE))
-            throw effect_exception{AL_INVALID_VALUE, "Chorus rate out of range"};
+            throw effect_exception{AL_INVALID_VALUE, "Chorus rate out of range: %f", val};
         props->Chorus.Rate = val;
         break;
 
     case AL_CHORUS_DEPTH:
         if(!(val >= AL_CHORUS_MIN_DEPTH && val <= AL_CHORUS_MAX_DEPTH))
-            throw effect_exception{AL_INVALID_VALUE, "Chorus depth out of range"};
+            throw effect_exception{AL_INVALID_VALUE, "Chorus depth out of range: %f", val};
         props->Chorus.Depth = val;
         break;
 
     case AL_CHORUS_FEEDBACK:
         if(!(val >= AL_CHORUS_MIN_FEEDBACK && val <= AL_CHORUS_MAX_FEEDBACK))
-            throw effect_exception{AL_INVALID_VALUE, "Chorus feedback out of range"};
+            throw effect_exception{AL_INVALID_VALUE, "Chorus feedback out of range: %f", val};
         props->Chorus.Feedback = val;
         break;
 
     case AL_CHORUS_DELAY:
         if(!(val >= AL_CHORUS_MIN_DELAY && val <= AL_CHORUS_MAX_DELAY))
-            throw effect_exception{AL_INVALID_VALUE, "Chorus delay out of range"};
+            throw effect_exception{AL_INVALID_VALUE, "Chorus delay out of range: %f", val};
         props->Chorus.Delay = val;
         break;
 
@@ -72,7 +97,7 @@ void Chorus_getParami(const EffectProps *props, ALenum param, int *val)
     switch(param)
     {
     case AL_CHORUS_WAVEFORM:
-        *val = props->Chorus.Waveform;
+        *val = EnumFromWaveform(props->Chorus.Waveform);
         break;
 
     case AL_CHORUS_PHASE:
@@ -115,7 +140,7 @@ void Chorus_getParamfv(const EffectProps *props, ALenum param, float *vals)
 const EffectProps genDefaultChorusProps() noexcept
 {
     EffectProps props{};
-    props.Chorus.Waveform = AL_CHORUS_DEFAULT_WAVEFORM;
+    props.Chorus.Waveform = *WaveformFromEnum(AL_CHORUS_DEFAULT_WAVEFORM);
     props.Chorus.Phase = AL_CHORUS_DEFAULT_PHASE;
     props.Chorus.Rate = AL_CHORUS_DEFAULT_RATE;
     props.Chorus.Depth = AL_CHORUS_DEFAULT_DEPTH;
@@ -130,14 +155,15 @@ void Flanger_setParami(EffectProps *props, ALenum param, int val)
     switch(param)
     {
     case AL_FLANGER_WAVEFORM:
-        if(!(val >= AL_FLANGER_MIN_WAVEFORM && val <= AL_FLANGER_MAX_WAVEFORM))
-            throw effect_exception{AL_INVALID_VALUE, "Invalid flanger waveform"};
-        props->Chorus.Waveform = val;
+        if(auto formopt = WaveformFromEnum(val))
+            props->Chorus.Waveform = *formopt;
+        else
+            throw effect_exception{AL_INVALID_VALUE, "Invalid flanger waveform: 0x%04x", val};
         break;
 
     case AL_FLANGER_PHASE:
         if(!(val >= AL_FLANGER_MIN_PHASE && val <= AL_FLANGER_MAX_PHASE))
-            throw effect_exception{AL_INVALID_VALUE, "Flanger phase out of range"};
+            throw effect_exception{AL_INVALID_VALUE, "Flanger phase out of range: %d", val};
         props->Chorus.Phase = val;
         break;
 
@@ -153,25 +179,25 @@ void Flanger_setParamf(EffectProps *props, ALenum param, float val)
     {
     case AL_FLANGER_RATE:
         if(!(val >= AL_FLANGER_MIN_RATE && val <= AL_FLANGER_MAX_RATE))
-            throw effect_exception{AL_INVALID_VALUE, "Flanger rate out of range"};
+            throw effect_exception{AL_INVALID_VALUE, "Flanger rate out of range: %f", val};
         props->Chorus.Rate = val;
         break;
 
     case AL_FLANGER_DEPTH:
         if(!(val >= AL_FLANGER_MIN_DEPTH && val <= AL_FLANGER_MAX_DEPTH))
-            throw effect_exception{AL_INVALID_VALUE, "Flanger depth out of range"};
+            throw effect_exception{AL_INVALID_VALUE, "Flanger depth out of range: %f", val};
         props->Chorus.Depth = val;
         break;
 
     case AL_FLANGER_FEEDBACK:
         if(!(val >= AL_FLANGER_MIN_FEEDBACK && val <= AL_FLANGER_MAX_FEEDBACK))
-            throw effect_exception{AL_INVALID_VALUE, "Flanger feedback out of range"};
+            throw effect_exception{AL_INVALID_VALUE, "Flanger feedback out of range: %f", val};
         props->Chorus.Feedback = val;
         break;
 
     case AL_FLANGER_DELAY:
         if(!(val >= AL_FLANGER_MIN_DELAY && val <= AL_FLANGER_MAX_DELAY))
-            throw effect_exception{AL_INVALID_VALUE, "Flanger delay out of range"};
+            throw effect_exception{AL_INVALID_VALUE, "Flanger delay out of range: %f", val};
         props->Chorus.Delay = val;
         break;
 
@@ -187,7 +213,7 @@ void Flanger_getParami(const EffectProps *props, ALenum param, int *val)
     switch(param)
     {
     case AL_FLANGER_WAVEFORM:
-        *val = props->Chorus.Waveform;
+        *val = EnumFromWaveform(props->Chorus.Waveform);
         break;
 
     case AL_FLANGER_PHASE:
@@ -230,7 +256,7 @@ void Flanger_getParamfv(const EffectProps *props, ALenum param, float *vals)
 EffectProps genDefaultFlangerProps() noexcept
 {
     EffectProps props{};
-    props.Chorus.Waveform = AL_FLANGER_DEFAULT_WAVEFORM;
+    props.Chorus.Waveform = *WaveformFromEnum(AL_FLANGER_DEFAULT_WAVEFORM);
     props.Chorus.Phase = AL_FLANGER_DEFAULT_PHASE;
     props.Chorus.Rate = AL_FLANGER_DEFAULT_RATE;
     props.Chorus.Depth = AL_FLANGER_DEFAULT_DEPTH;
diff --git a/al/effects/echo.cpp b/al/effects/echo.cpp
index b242a9cd..79a60521 100644
--- a/al/effects/echo.cpp
+++ b/al/effects/echo.cpp
@@ -10,6 +10,9 @@
 
 namespace {
 
+static_assert(EchoMaxDelay >= AL_ECHO_MAX_DELAY, "Echo max delay too short");
+static_assert(EchoMaxLRDelay >= AL_ECHO_MAX_LRDELAY, "Echo max left-right delay too short");
+
 void Echo_setParami(EffectProps*, ALenum param, int)
 { throw effect_exception{AL_INVALID_ENUM, "Invalid echo integer property 0x%04x", param}; }
 void Echo_setParamiv(EffectProps*, ALenum param, const int*)
diff --git a/al/effects/fshifter.cpp b/al/effects/fshifter.cpp
index 31138fe6..444b0260 100644
--- a/al/effects/fshifter.cpp
+++ b/al/effects/fshifter.cpp
@@ -4,12 +4,34 @@
 #include "AL/al.h"
 #include "AL/efx.h"
 
+#include "aloptional.h"
 #include "effects.h"
 #include "effects/base.h"
 
 
 namespace {
 
+al::optional<FShifterDirection> DirectionFromEmum(ALenum value)
+{
+    switch(value)
+    {
+    case AL_FREQUENCY_SHIFTER_DIRECTION_DOWN: return al::make_optional(FShifterDirection::Down);
+    case AL_FREQUENCY_SHIFTER_DIRECTION_UP: return al::make_optional(FShifterDirection::Up);
+    case AL_FREQUENCY_SHIFTER_DIRECTION_OFF: return al::make_optional(FShifterDirection::Off);
+    }
+    return al::nullopt;
+}
+ALenum EnumFromDirection(FShifterDirection dir)
+{
+    switch(dir)
+    {
+    case FShifterDirection::Down: return AL_FREQUENCY_SHIFTER_DIRECTION_DOWN;
+    case FShifterDirection::Up: return AL_FREQUENCY_SHIFTER_DIRECTION_UP;
+    case FShifterDirection::Off: return AL_FREQUENCY_SHIFTER_DIRECTION_OFF;
+    }
+    throw std::runtime_error{"Invalid direction: "+std::to_string(static_cast<int>(dir))};
+}
+
 void Fshifter_setParamf(EffectProps *props, ALenum param, float val)
 {
     switch(param)
@@ -33,17 +55,19 @@ void Fshifter_setParami(EffectProps *props, ALenum param, int val)
     switch(param)
     {
     case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION:
-        if(!(val >= AL_FREQUENCY_SHIFTER_MIN_LEFT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_LEFT_DIRECTION))
+        if(auto diropt = DirectionFromEmum(val))
+            props->Fshifter.LeftDirection = *diropt;
+        else
             throw effect_exception{AL_INVALID_VALUE,
-                "Frequency shifter left direction out of range"};
-        props->Fshifter.LeftDirection = val;
+                "Unsupported frequency shifter left direction: 0x%04x", val};
         break;
 
     case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION:
-        if(!(val >= AL_FREQUENCY_SHIFTER_MIN_RIGHT_DIRECTION && val <= AL_FREQUENCY_SHIFTER_MAX_RIGHT_DIRECTION))
+        if(auto diropt = DirectionFromEmum(val))
+            props->Fshifter.RightDirection = *diropt;
+        else
             throw effect_exception{AL_INVALID_VALUE,
-                "Frequency shifter right direction out of range"};
-        props->Fshifter.RightDirection = val;
+                "Unsupported frequency shifter right direction: 0x%04x", val};
         break;
 
     default:
@@ -59,10 +83,10 @@ void Fshifter_getParami(const EffectProps *props, ALenum param, int *val)
     switch(param)
     {
     case AL_FREQUENCY_SHIFTER_LEFT_DIRECTION:
-        *val = props->Fshifter.LeftDirection;
+        *val = EnumFromDirection(props->Fshifter.LeftDirection);
         break;
     case AL_FREQUENCY_SHIFTER_RIGHT_DIRECTION:
-        *val = props->Fshifter.RightDirection;
+        *val = EnumFromDirection(props->Fshifter.RightDirection);
         break;
     default:
         throw effect_exception{AL_INVALID_ENUM,
@@ -92,8 +116,8 @@ EffectProps genDefaultProps() noexcept
 {
     EffectProps props{};
     props.Fshifter.Frequency      = AL_FREQUENCY_SHIFTER_DEFAULT_FREQUENCY;
-    props.Fshifter.LeftDirection  = AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION;
-    props.Fshifter.RightDirection = AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION;
+    props.Fshifter.LeftDirection  = *DirectionFromEmum(AL_FREQUENCY_SHIFTER_DEFAULT_LEFT_DIRECTION);
+    props.Fshifter.RightDirection = *DirectionFromEmum(AL_FREQUENCY_SHIFTER_DEFAULT_RIGHT_DIRECTION);
     return props;
 }
 
diff --git a/al/effects/modulator.cpp b/al/effects/modulator.cpp
index 95f379e2..89dcc209 100644
--- a/al/effects/modulator.cpp
+++ b/al/effects/modulator.cpp
@@ -4,25 +4,48 @@
 #include "AL/al.h"
 #include "AL/efx.h"
 
+#include "aloptional.h"
 #include "effects.h"
 #include "effects/base.h"
 
 
 namespace {
 
+al::optional<ModulatorWaveform> WaveformFromEmum(ALenum value)
+{
+    switch(value)
+    {
+    case AL_RING_MODULATOR_SINUSOID: return al::make_optional(ModulatorWaveform::Sinusoid);
+    case AL_RING_MODULATOR_SAWTOOTH: return al::make_optional(ModulatorWaveform::Sawtooth);
+    case AL_RING_MODULATOR_SQUARE: return al::make_optional(ModulatorWaveform::Square);
+    }
+    return al::nullopt;
+}
+ALenum EnumFromWaveform(ModulatorWaveform type)
+{
+    switch(type)
+    {
+    case ModulatorWaveform::Sinusoid: return AL_RING_MODULATOR_SINUSOID;
+    case ModulatorWaveform::Sawtooth: return AL_RING_MODULATOR_SAWTOOTH;
+    case ModulatorWaveform::Square: return AL_RING_MODULATOR_SQUARE;
+    }
+    throw std::runtime_error{"Invalid modulator waveform: " +
+        std::to_string(static_cast<int>(type))};
+}
+
 void Modulator_setParamf(EffectProps *props, ALenum param, float val)
 {
     switch(param)
     {
     case AL_RING_MODULATOR_FREQUENCY:
         if(!(val >= AL_RING_MODULATOR_MIN_FREQUENCY && val <= AL_RING_MODULATOR_MAX_FREQUENCY))
-            throw effect_exception{AL_INVALID_VALUE, "Modulator frequency out of range"};
+            throw effect_exception{AL_INVALID_VALUE, "Modulator frequency out of range: %f", val};
         props->Modulator.Frequency = val;
         break;
 
     case AL_RING_MODULATOR_HIGHPASS_CUTOFF:
         if(!(val >= AL_RING_MODULATOR_MIN_HIGHPASS_CUTOFF && val <= AL_RING_MODULATOR_MAX_HIGHPASS_CUTOFF))
-            throw effect_exception{AL_INVALID_VALUE, "Modulator high-pass cutoff out of range"};
+            throw effect_exception{AL_INVALID_VALUE, "Modulator high-pass cutoff out of range: %f", val};
         props->Modulator.HighPassCutoff = val;
         break;
 
@@ -42,9 +65,10 @@ void Modulator_setParami(EffectProps *props, ALenum param, int val)
         break;
 
     case AL_RING_MODULATOR_WAVEFORM:
-        if(!(val >= AL_RING_MODULATOR_MIN_WAVEFORM && val <= AL_RING_MODULATOR_MAX_WAVEFORM))
-            throw effect_exception{AL_INVALID_VALUE, "Invalid modulator waveform"};
-        props->Modulator.Waveform = val;
+        if(auto formopt = WaveformFromEmum(val))
+            props->Modulator.Waveform = *formopt;
+        else
+            throw effect_exception{AL_INVALID_VALUE, "Invalid modulator waveform: 0x%04x", val};
         break;
 
     default:
@@ -66,7 +90,7 @@ void Modulator_getParami(const EffectProps *props, ALenum param, int *val)
         *val = static_cast<int>(props->Modulator.HighPassCutoff);
         break;
     case AL_RING_MODULATOR_WAVEFORM:
-        *val = props->Modulator.Waveform;
+        *val = EnumFromWaveform(props->Modulator.Waveform);
         break;
 
     default:
@@ -99,7 +123,7 @@ EffectProps genDefaultProps() noexcept
     EffectProps props{};
     props.Modulator.Frequency      = AL_RING_MODULATOR_DEFAULT_FREQUENCY;
     props.Modulator.HighPassCutoff = AL_RING_MODULATOR_DEFAULT_HIGHPASS_CUTOFF;
-    props.Modulator.Waveform       = AL_RING_MODULATOR_DEFAULT_WAVEFORM;
+    props.Modulator.Waveform       = *WaveformFromEmum(AL_RING_MODULATOR_DEFAULT_WAVEFORM);
     return props;
 }
 
diff --git a/al/effects/vmorpher.cpp b/al/effects/vmorpher.cpp
index f6b73705..03eb2c62 100644
--- a/al/effects/vmorpher.cpp
+++ b/al/effects/vmorpher.cpp
@@ -4,32 +4,124 @@
 #include "AL/al.h"
 #include "AL/efx.h"
 
+#include "aloptional.h"
 #include "effects.h"
 #include "effects/base.h"
 
 
 namespace {
 
+al::optional<VMorpherPhenome> PhenomeFromEnum(ALenum val)
+{
+#define HANDLE_PHENOME(x) case AL_VOCAL_MORPHER_PHONEME_ ## x:                \
+    return al::make_optional(VMorpherPhenome::x)
+    switch(val)
+    {
+    HANDLE_PHENOME(A);
+    HANDLE_PHENOME(E);
+    HANDLE_PHENOME(I);
+    HANDLE_PHENOME(O);
+    HANDLE_PHENOME(U);
+    HANDLE_PHENOME(AA);
+    HANDLE_PHENOME(AE);
+    HANDLE_PHENOME(AH);
+    HANDLE_PHENOME(AO);
+    HANDLE_PHENOME(EH);
+    HANDLE_PHENOME(ER);
+    HANDLE_PHENOME(IH);
+    HANDLE_PHENOME(IY);
+    HANDLE_PHENOME(UH);
+    HANDLE_PHENOME(UW);
+    HANDLE_PHENOME(B);
+    HANDLE_PHENOME(D);
+    HANDLE_PHENOME(F);
+    HANDLE_PHENOME(G);
+    HANDLE_PHENOME(J);
+    HANDLE_PHENOME(K);
+    HANDLE_PHENOME(L);
+    HANDLE_PHENOME(M);
+    HANDLE_PHENOME(N);
+    HANDLE_PHENOME(P);
+    HANDLE_PHENOME(R);
+    HANDLE_PHENOME(S);
+    HANDLE_PHENOME(T);
+    HANDLE_PHENOME(V);
+    HANDLE_PHENOME(Z);
+    }
+    return al::nullopt;
+#undef HANDLE_PHENOME
+}
+ALenum EnumFromPhenome(VMorpherPhenome phenome)
+{
+#define HANDLE_PHENOME(x) case VMorpherPhenome::x: return AL_VOCAL_MORPHER_PHONEME_ ## x
+    switch(phenome)
+    {
+    HANDLE_PHENOME(A);
+    HANDLE_PHENOME(E);
+    HANDLE_PHENOME(I);
+    HANDLE_PHENOME(O);
+    HANDLE_PHENOME(U);
+    HANDLE_PHENOME(AA);
+    HANDLE_PHENOME(AE);
+    HANDLE_PHENOME(AH);
+    HANDLE_PHENOME(AO);
+    HANDLE_PHENOME(EH);
+    HANDLE_PHENOME(ER);
+    HANDLE_PHENOME(IH);
+    HANDLE_PHENOME(IY);
+    HANDLE_PHENOME(UH);
+    HANDLE_PHENOME(UW);
+    HANDLE_PHENOME(B);
+    HANDLE_PHENOME(D);
+    HANDLE_PHENOME(F);
+    HANDLE_PHENOME(G);
+    HANDLE_PHENOME(J);
+    HANDLE_PHENOME(K);
+    HANDLE_PHENOME(L);
+    HANDLE_PHENOME(M);
+    HANDLE_PHENOME(N);
+    HANDLE_PHENOME(P);
+    HANDLE_PHENOME(R);
+    HANDLE_PHENOME(S);
+    HANDLE_PHENOME(T);
+    HANDLE_PHENOME(V);
+    HANDLE_PHENOME(Z);
+    }
+    throw std::runtime_error{"Invalid phenome: "+std::to_string(static_cast<int>(phenome))};
+#undef HANDLE_PHENOME
+}
+
+al::optional<VMorpherWaveform> WaveformFromEmum(ALenum value)
+{
+    switch(value)
+    {
+    case AL_VOCAL_MORPHER_WAVEFORM_SINUSOID: return al::make_optional(VMorpherWaveform::Sinusoid);
+    case AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE: return al::make_optional(VMorpherWaveform::Triangle);
+    case AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH: return al::make_optional(VMorpherWaveform::Sawtooth);
+    }
+    return al::nullopt;
+}
+ALenum EnumFromWaveform(VMorpherWaveform type)
+{
+    switch(type)
+    {
+    case VMorpherWaveform::Sinusoid: return AL_VOCAL_MORPHER_WAVEFORM_SINUSOID;
+    case VMorpherWaveform::Triangle: return AL_VOCAL_MORPHER_WAVEFORM_TRIANGLE;
+    case VMorpherWaveform::Sawtooth: return AL_VOCAL_MORPHER_WAVEFORM_SAWTOOTH;
+    }
+    throw std::runtime_error{"Invalid vocal morpher waveform: " +
+        std::to_string(static_cast<int>(type))};
+}
+
 void Vmorpher_setParami(EffectProps *props, ALenum param, int val)
 {
     switch(param)
     {
-    case AL_VOCAL_MORPHER_WAVEFORM:
-        if(!(val >= AL_VOCAL_MORPHER_MIN_WAVEFORM && val <= AL_VOCAL_MORPHER_MAX_WAVEFORM))
-            throw effect_exception{AL_INVALID_VALUE, "Vocal morpher waveform out of range"};
-        props->Vmorpher.Waveform = val;
-        break;
-
     case AL_VOCAL_MORPHER_PHONEMEA:
-        if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEA && val <= AL_VOCAL_MORPHER_MAX_PHONEMEA))
-            throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-a out of range"};
-        props->Vmorpher.PhonemeA = val;
-        break;
-
-    case AL_VOCAL_MORPHER_PHONEMEB:
-        if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEB && val <= AL_VOCAL_MORPHER_MAX_PHONEMEB))
-            throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-b out of range"};
-        props->Vmorpher.PhonemeB = val;
+        if(auto phenomeopt = PhenomeFromEnum(val))
+            props->Vmorpher.PhonemeA = *phenomeopt;
+        else
+            throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-a out of range: 0x%04x", val};
         break;
 
     case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING:
@@ -38,12 +130,26 @@ void Vmorpher_setParami(EffectProps *props, ALenum param, int val)
         props->Vmorpher.PhonemeACoarseTuning = val;
         break;
 
+    case AL_VOCAL_MORPHER_PHONEMEB:
+        if(auto phenomeopt = PhenomeFromEnum(val))
+            props->Vmorpher.PhonemeB = *phenomeopt;
+        else
+            throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-b out of range: 0x%04x", val};
+        break;
+
     case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING:
         if(!(val >= AL_VOCAL_MORPHER_MIN_PHONEMEB_COARSE_TUNING && val <= AL_VOCAL_MORPHER_MAX_PHONEMEB_COARSE_TUNING))
             throw effect_exception{AL_INVALID_VALUE, "Vocal morpher phoneme-b coarse tuning out of range"};
         props->Vmorpher.PhonemeBCoarseTuning = val;
         break;
 
+    case AL_VOCAL_MORPHER_WAVEFORM:
+        if(auto formopt = WaveformFromEmum(val))
+            props->Vmorpher.Waveform = *formopt;
+        else
+            throw effect_exception{AL_INVALID_VALUE, "Vocal morpher waveform out of range: 0x%04x", val};
+        break;
+
     default:
         throw effect_exception{AL_INVALID_ENUM, "Invalid vocal morpher integer property 0x%04x",
             param};
@@ -77,23 +183,23 @@ void Vmorpher_getParami(const EffectProps *props, ALenum param, int* val)
     switch(param)
     {
     case AL_VOCAL_MORPHER_PHONEMEA:
-        *val = props->Vmorpher.PhonemeA;
-        break;
-
-    case AL_VOCAL_MORPHER_PHONEMEB:
-        *val = props->Vmorpher.PhonemeB;
+        *val = EnumFromPhenome(props->Vmorpher.PhonemeA);
         break;
 
     case AL_VOCAL_MORPHER_PHONEMEA_COARSE_TUNING:
         *val = props->Vmorpher.PhonemeACoarseTuning;
         break;
 
+    case AL_VOCAL_MORPHER_PHONEMEB:
+        *val = EnumFromPhenome(props->Vmorpher.PhonemeB);
+        break;
+
     case AL_VOCAL_MORPHER_PHONEMEB_COARSE_TUNING:
         *val = props->Vmorpher.PhonemeBCoarseTuning;
         break;
 
     case AL_VOCAL_MORPHER_WAVEFORM:
-        *val = props->Vmorpher.Waveform;
+        *val = EnumFromWaveform(props->Vmorpher.Waveform);
         break;
 
     default:
@@ -126,11 +232,11 @@ EffectProps genDefaultProps() noexcept
 {
     EffectProps props{};
     props.Vmorpher.Rate                 = AL_VOCAL_MORPHER_DEFAULT_RATE;
-    props.Vmorpher.PhonemeA             = AL_VOCAL_MORPHER_DEFAULT_PHONEMEA;
-    props.Vmorpher.PhonemeB             = AL_VOCAL_MORPHER_DEFAULT_PHONEMEB;
+    props.Vmorpher.PhonemeA             = *PhenomeFromEnum(AL_VOCAL_MORPHER_DEFAULT_PHONEMEA);
+    props.Vmorpher.PhonemeB             = *PhenomeFromEnum(AL_VOCAL_MORPHER_DEFAULT_PHONEMEB);
     props.Vmorpher.PhonemeACoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEA_COARSE_TUNING;
     props.Vmorpher.PhonemeBCoarseTuning = AL_VOCAL_MORPHER_DEFAULT_PHONEMEB_COARSE_TUNING;
-    props.Vmorpher.Waveform             = AL_VOCAL_MORPHER_DEFAULT_WAVEFORM;
+    props.Vmorpher.Waveform             = *WaveformFromEmum(AL_VOCAL_MORPHER_DEFAULT_WAVEFORM);
     return props;
 }
 
-- 
cgit v1.2.3