You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

361 lines
15KB

  1. #include "FrozenWasteland.hpp"
  2. #include "dsp/decimator.hpp"
  3. #include "dsp/digital.hpp"
  4. #include "StateVariableFilter.h"
  5. using namespace std;
  6. #define BANDS 5
  7. namespace rack_plugin_FrozenWasteland {
  8. struct VoxInhumana : Module {
  9. typedef float T;
  10. enum ParamIds {
  11. VOWEL_1_PARAM,
  12. VOWEL_2_PARAM,
  13. VOWEL_BALANCE_PARAM,
  14. VOICE_TYPE_PARAM,
  15. FC_MAIN_CUTOFF_PARAM,
  16. FREQ_1_CUTOFF_PARAM,
  17. FREQ_2_CUTOFF_PARAM,
  18. FREQ_3_CUTOFF_PARAM,
  19. FREQ_4_CUTOFF_PARAM,
  20. FREQ_5_CUTOFF_PARAM,
  21. AMP_1_PARAM,
  22. AMP_2_PARAM,
  23. AMP_3_PARAM,
  24. AMP_4_PARAM,
  25. AMP_5_PARAM,
  26. VOWEL_1_ATTENUVERTER_PARAM,
  27. VOWEL_2_ATTENUVERTER_PARAM,
  28. VOWEL_BALANCE_ATTENUVERTER_PARAM,
  29. VOICE_TYPE_ATTENUVERTER_PARAM,
  30. FC_MAIN_ATTENUVERTER_PARAM,
  31. FREQ_1_CV_ATTENUVERTER_PARAM,
  32. FREQ_2_CV_ATTENUVERTER_PARAM,
  33. FREQ_3_CV_ATTENUVERTER_PARAM,
  34. FREQ_4_CV_ATTENUVERTER_PARAM,
  35. FREQ_5_CV_ATTENUVERTER_PARAM,
  36. AMP_1_CV_ATTENUVERTER_PARAM,
  37. AMP_2_CV_ATTENUVERTER_PARAM,
  38. AMP_3_CV_ATTENUVERTER_PARAM,
  39. AMP_4_CV_ATTENUVERTER_PARAM,
  40. AMP_5_CV_ATTENUVERTER_PARAM,
  41. NUM_PARAMS
  42. };
  43. enum InputIds {
  44. SIGNAL_IN,
  45. VOWEL_1_CV_IN,
  46. VOWEL_2_CV_IN,
  47. VOWEL_BALANCE_CV_IN,
  48. VOICE_TYPE_CV_IN,
  49. FC_MAIN_CV_IN,
  50. FREQ_1_CUTOFF_INPUT,
  51. FREQ_2_CUTOFF_INPUT,
  52. FREQ_3_CUTOFF_INPUT,
  53. FREQ_4_CUTOFF_INPUT,
  54. FREQ_5_CUTOFF_INPUT,
  55. AMP_1_INPUT,
  56. AMP_2_INPUT,
  57. AMP_3_INPUT,
  58. AMP_4_INPUT,
  59. AMP_5_INPUT,
  60. NUM_INPUTS
  61. };
  62. enum OutputIds {
  63. VOX_OUTPUT,
  64. NUM_OUTPUTS
  65. };
  66. enum LightIds {
  67. VOWEL_1_LIGHT,
  68. VOWEL_2_LIGHT,
  69. NUM_LIGHTS
  70. };
  71. StateVariableFilterState<T> filterStates[BANDS];
  72. StateVariableFilterParams<T> filterParams[BANDS];
  73. float freq[BANDS] = {0};
  74. float lastFreq[BANDS] = {0};
  75. float Q[BANDS] = {0};
  76. float lastQ[BANDS] = {0};
  77. float peak[BANDS] = {0};
  78. int vowel1 = 0;
  79. int vowel2 = 0;
  80. float vowelBalance = 0;
  81. int voiceType = 0;
  82. float fcShift = 0;
  83. float lerp(float v0, float v1, float t) {
  84. return (1 - t) * v0 + t * v1;
  85. }
  86. // First Index is Voice Type (soprano,alto,counter-tenor,tenor,bass)
  87. // Second Index is Vowel (a,e,i,o,u) // should find more
  88. // Third if filter/formant index
  89. // Fourth: Cutoff,Q,Peak db)
  90. const float formantParameters[5][5][BANDS][3] = {
  91. //Bass
  92. {
  93. {{600,10,0},{1040,15,-7},{2250,21,-9},{2450,20,-9},{2750,21,-20}}, //a
  94. {{400,10,0},{1620,20,-12},{2400,24,-9},{2800,23,-12},{3100,26,-18}}, //e
  95. {{250,4,0},{1750,19,-30},{2600,26,-16},{3050,25,-22},{3340,28,-28}}, //i
  96. {{400,10,0},{750,9,-11},{2400,24,-21},{2600,22,-20},{2900,24,-40}}, //o
  97. {{350,9,0},{600,8,-20},{2400,24,-32},{2675,22,-28},{2950,25,-36}}, //u
  98. },
  99. //Tenor - in progress
  100. {
  101. {{650,8,0},{1080,12,-6},{2650,22,-7},{2900,22,-8},{3250,23,-22}}, //a
  102. {{400,6,0},{1700,21,-14},{2600,26,-12},{3200,27,-14},{3580,30,-20}}, //e
  103. {{290,7,0},{1870,21,-15},{2800,28,-18},{3250,27,-20},{3540,30,-30}}, //i
  104. {{400,10,0},{800,10,-10},{2600,26,-12},{2800,23,-12},{3000,25,-26}}, //o
  105. {{350,9,0},{600,10,-20},{2700,27,-17},{2900,24,-14},{3300,28,-26}}, //u
  106. },
  107. //Counter-Tenor - in progress
  108. {
  109. {{660,8,0},{1120,12,-6},{2750,23,-23},{3000,23,-24},{3350,24,-38}}, //a
  110. {{440,6,0},{1800,22,-14},{2700,27,-18},{3000,25,-20},{3300,28,-20}}, //e
  111. {{270,7,0},{1850,21,-24},{2900,29,-24},{3350,28,-36},{3590,30,-36}}, //i
  112. {{430,11,0},{820,10,-10},{2700,27,-26},{3000,25,-22},{3300,28,-34}}, //o
  113. {{370,9,0},{630,11,-20},{2750,28,-23},{3000,25,-30},{3400,28,-34}}, //u
  114. },
  115. //Alto
  116. {
  117. {{800,10,0},{1150,13,-4},{2800,27,-20},{3500,27,-36},{4950,35,-60}}, //a
  118. {{400,7,0},{1600,20,-24},{2700,23,-30},{3300,22,-35},{4950,25,-60}}, //e
  119. {{350,7,0},{1700,17,-20},{2700,23,-30},{3700,25,-36},{4950,25,-60}}, //i
  120. {{450,6,0},{800,10,-9},{2830,28,-16},{3500,27,-28},{4950,37,-55}}, //o
  121. {{325,7,0},{700,12,-12},{2530,15,-30},{3500,19,-40},{4950,25,-64}}, //u
  122. },
  123. //Soprano
  124. {
  125. {{800,10,0},{1150,12,-6},{2900,24,-32},{3900,30,-20},{4950,35,-50}}, //a
  126. {{350,6,0},{2000,20,-20},{2800,23,-15},{3600,24,-40},{4950,25,-56}}, //e
  127. {{270,5,0},{2140,24,-12},{2950,30,-26},{3900,33,-26},{4950,41,-44}}, //i
  128. {{450,6,0},{800,10,-11},{2830,28,-22},{3800,29,-22},{4950,37,-50}}, //o
  129. {{325,7,0},{700,12,-16},{2700,16,-35},{3800,21,-40},{4950,25,-60}}, //u
  130. }
  131. };
  132. VoxInhumana() : Module(NUM_PARAMS, NUM_INPUTS, NUM_OUTPUTS, NUM_LIGHTS) {
  133. for (int i = 0; i < BANDS; ++i) {
  134. filterParams[i].setMode(StateVariableFilterParams<T>::Mode::BandPass);
  135. filterParams[i].setQ(5);
  136. filterParams[i].setFreq(T(.1));
  137. }
  138. }
  139. void reset() override;
  140. void step() override;
  141. };
  142. void VoxInhumana::reset() {
  143. params[FC_MAIN_CUTOFF_PARAM].value = 1.0f;
  144. params[VOWEL_BALANCE_PARAM].value = 0.0f;
  145. for(int i = 0;i<BANDS;i++) {
  146. params[FREQ_1_CUTOFF_PARAM+i].value = 0.0f;
  147. params[AMP_1_PARAM + i].value = 1.0f;
  148. }
  149. }
  150. void VoxInhumana::step() {
  151. float signalIn = inputs[SIGNAL_IN].value/5.0f;
  152. vowel1 = (int)clamp(params[VOWEL_1_PARAM].value + (inputs[VOWEL_1_CV_IN].value * params[VOWEL_1_ATTENUVERTER_PARAM].value),0.0f,4.0f);
  153. vowel2 = (int)clamp(params[VOWEL_2_PARAM].value + (inputs[VOWEL_2_CV_IN].value * params[VOWEL_2_ATTENUVERTER_PARAM].value),0.0f,4.0f);
  154. vowelBalance = clamp(params[VOWEL_BALANCE_PARAM].value + (inputs[VOWEL_BALANCE_CV_IN].value * params[VOWEL_BALANCE_ATTENUVERTER_PARAM].value /10.0f),0.0f,1.0f);
  155. voiceType = (int)clamp(params[VOICE_TYPE_PARAM].value + (inputs[VOICE_TYPE_CV_IN].value * params[VOICE_TYPE_ATTENUVERTER_PARAM].value),0.0f,4.0f);
  156. fcShift = clamp(params[FC_MAIN_CUTOFF_PARAM].value + (inputs[FC_MAIN_CV_IN].value * params[FC_MAIN_ATTENUVERTER_PARAM].value/10.0f) ,0.0f,2.0f);
  157. lights[VOWEL_1_LIGHT].value = 1.0-vowelBalance;
  158. lights[VOWEL_2_LIGHT].value = vowelBalance;
  159. for (int i=0; i<BANDS;i++) {
  160. float cutoffExp = params[FREQ_1_CUTOFF_PARAM+i].value + inputs[FREQ_1_CUTOFF_INPUT+i].value * params[FREQ_1_CV_ATTENUVERTER_PARAM+i].value;
  161. cutoffExp = clamp(cutoffExp, -1.0f, 1.0f);
  162. freq[i] = lerp(formantParameters[voiceType][vowel1][i][0],formantParameters[voiceType][vowel2][i][0],vowelBalance);
  163. //Apply individual formant CV
  164. freq[i] = freq[i] + (freq[i] / 2 * cutoffExp); //Formant CV can alter formant by +/- 50%
  165. //Apply global Fc shift
  166. freq[i] = freq[i] * fcShift; //Global can double or really lower freq
  167. Q[i] = lerp(formantParameters[voiceType][vowel1][i][1],formantParameters[voiceType][vowel2][i][1],vowelBalance);
  168. peak[i] = lerp(formantParameters[voiceType][vowel1][i][2],formantParameters[voiceType][vowel2][i][2],vowelBalance);
  169. if(freq[i] != lastFreq[i]) {
  170. float Fc = freq[i] / engineGetSampleRate();
  171. filterParams[i].setFreq(T(Fc));
  172. lastFreq[i] = freq[i];
  173. }
  174. if(Q[i] != lastQ[i]) {
  175. filterParams[i].setQ(Q[i]);
  176. lastQ[i] = Q[i];
  177. }
  178. }
  179. float out = 0.0f;
  180. for(int i=0;i<BANDS;i++) {
  181. float filterOut = StateVariableFilter<T>::run(signalIn, filterStates[i], filterParams[i]);;
  182. float attenuation = powf(10,peak[i] / 20.0f);
  183. float manualAttenuation = params[AMP_1_PARAM+i].value + inputs[AMP_1_INPUT+i].value * params[AMP_1_CV_ATTENUVERTER_PARAM+i].value;
  184. attenuation = clamp(attenuation * manualAttenuation, 0.0f, 1.0f);
  185. out += filterOut * attenuation * 5.0f;
  186. }
  187. outputs[VOX_OUTPUT].value = out / 5.0f;
  188. }
  189. struct VoxInhumanaBandDisplay : TransparentWidget {
  190. VoxInhumana *module;
  191. int frame = 0;
  192. std::shared_ptr<Font> font;
  193. VoxInhumanaBandDisplay() {
  194. font = Font::load(assetPlugin(plugin, "res/fonts/DejaVuSansMono.ttf"));
  195. }
  196. void drawVowel(NVGcontext *vg, Vec pos, int vowel) {
  197. nvgFontSize(vg, 22);
  198. nvgFontFaceId(vg, font->handle);
  199. nvgTextLetterSpacing(vg, -2);
  200. const char* vowelNames[5] = {"A","E","I","O","U"};
  201. nvgFillColor(vg, nvgRGBA(0x00, 0xaf, 0x00, 0xff));
  202. char text[128];
  203. snprintf(text, sizeof(text), "%s", vowelNames[vowel]);
  204. nvgText(vg, pos.x + 8, pos.y, text, NULL);
  205. }
  206. void drawVoiceType(NVGcontext *vg, Vec pos, int voiceType) {
  207. nvgFontSize(vg, 14);
  208. nvgFontFaceId(vg, font->handle);
  209. nvgTextLetterSpacing(vg, -2);
  210. const char* voiceNames[5] = {"Bass","Tenor","Counter-Tenor","Alto","Soprano"};
  211. nvgFillColor(vg, nvgRGBA(0x00, 0x8f, 0xff, 0xff));
  212. char text[128];
  213. snprintf(text, sizeof(text), "%s", voiceNames[voiceType]);
  214. nvgText(vg, pos.x + 8, pos.y, text, NULL);
  215. }
  216. void draw(NVGcontext *vg) override {
  217. drawVowel(vg, Vec(24.0, box.size.y - 99),module->vowel1);
  218. drawVowel(vg, Vec(156.0, box.size.y - 99),module->vowel2);
  219. drawVoiceType(vg, Vec(20.0, box.size.y - 27),module->voiceType);
  220. }
  221. };
  222. struct VoxInhumanaWidget : ModuleWidget {
  223. VoxInhumanaWidget(VoxInhumana *module);
  224. };
  225. VoxInhumanaWidget::VoxInhumanaWidget(VoxInhumana *module) : ModuleWidget(module) {
  226. box.size = Vec(15*14, 380);
  227. {
  228. SVGPanel *panel = new SVGPanel();
  229. panel->box.size = box.size;
  230. panel->setBackground(SVG::load(assetPlugin(plugin, "res/VoxInhumana.svg")));
  231. addChild(panel);
  232. }
  233. {
  234. VoxInhumanaBandDisplay *offsetDisplay = new VoxInhumanaBandDisplay();
  235. offsetDisplay->module = module;
  236. offsetDisplay->box.pos = Vec(15, 10);
  237. offsetDisplay->box.size = Vec(box.size.x, 140);
  238. addChild(offsetDisplay);
  239. }
  240. addParam(ParamWidget::create<RoundBlackKnob>(Vec(10, 30), module, VoxInhumana::VOWEL_1_PARAM, 0, 4.6, 0));
  241. addParam(ParamWidget::create<RoundBlackKnob>(Vec(140, 30), module, VoxInhumana::VOWEL_2_PARAM, 0, 4.6, 0));
  242. addParam(ParamWidget::create<RoundBlackKnob>(Vec(89, 30), module, VoxInhumana::VOWEL_BALANCE_PARAM, 0.0, 1.0, 0));
  243. addParam(ParamWidget::create<RoundBlackKnob>(Vec(7, 103), module, VoxInhumana::VOICE_TYPE_PARAM, 0, 4.6, 0));
  244. addParam(ParamWidget::create<RoundBlackKnob>(Vec(140, 103), module, VoxInhumana::FC_MAIN_CUTOFF_PARAM, 0.0, 2.0, 1));
  245. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(40, 62), module, VoxInhumana::VOWEL_1_ATTENUVERTER_PARAM, -1.0, 1.0, 0));
  246. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(170, 62), module, VoxInhumana::VOWEL_2_ATTENUVERTER_PARAM, -1.0, 1.0, 0));
  247. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(107, 62), module, VoxInhumana::VOWEL_BALANCE_ATTENUVERTER_PARAM, -1.0, 1.0, 0));
  248. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(31, 134), module, VoxInhumana::VOICE_TYPE_ATTENUVERTER_PARAM, -1.0, 1.0, 0));
  249. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(169, 125), module, VoxInhumana::FC_MAIN_ATTENUVERTER_PARAM, -1.0, 1.0, 0));
  250. addParam(ParamWidget::create<RoundBlackKnob>(Vec(15, 160), module, VoxInhumana::FREQ_1_CUTOFF_PARAM, -1.0, 1.0, 0));
  251. addParam(ParamWidget::create<RoundBlackKnob>(Vec(15, 195), module, VoxInhumana::FREQ_2_CUTOFF_PARAM, -1.0, 1.0, 0));
  252. addParam(ParamWidget::create<RoundBlackKnob>(Vec(15, 230), module, VoxInhumana::FREQ_3_CUTOFF_PARAM, -1.0, 1.0, 0));
  253. addParam(ParamWidget::create<RoundBlackKnob>(Vec(15, 265), module, VoxInhumana::FREQ_4_CUTOFF_PARAM, -1.0, 1.0, 0));
  254. addParam(ParamWidget::create<RoundBlackKnob>(Vec(15, 300), module, VoxInhumana::FREQ_5_CUTOFF_PARAM, -1.0, 1.0, 0));
  255. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(80, 162), module, VoxInhumana::FREQ_1_CV_ATTENUVERTER_PARAM, -1.0, 1.0, 0));
  256. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(80, 197), module, VoxInhumana::FREQ_2_CV_ATTENUVERTER_PARAM, -1.0, 1.0, 0));
  257. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(80, 232), module, VoxInhumana::FREQ_3_CV_ATTENUVERTER_PARAM, -1.0, 1.0, 0));
  258. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(80, 267), module, VoxInhumana::FREQ_4_CV_ATTENUVERTER_PARAM, -1.0, 1.0, 0));
  259. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(80, 302), module, VoxInhumana::FREQ_5_CV_ATTENUVERTER_PARAM, -1.0, 1.0, 0));
  260. addParam(ParamWidget::create<RoundBlackKnob>(Vec(110, 160), module, VoxInhumana::AMP_1_PARAM, 0.0, 2.0, 1));
  261. addParam(ParamWidget::create<RoundBlackKnob>(Vec(110, 195), module, VoxInhumana::AMP_2_PARAM, 0.0, 2.0, 1));
  262. addParam(ParamWidget::create<RoundBlackKnob>(Vec(110, 230), module, VoxInhumana::AMP_3_PARAM, 0.0, 2.0, 1));
  263. addParam(ParamWidget::create<RoundBlackKnob>(Vec(110, 265), module, VoxInhumana::AMP_4_PARAM, 0.0, 2.0, 1));
  264. addParam(ParamWidget::create<RoundBlackKnob>(Vec(110, 300), module, VoxInhumana::AMP_5_PARAM, 0.0, 2.0, 1));
  265. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(175, 162), module, VoxInhumana::AMP_1_CV_ATTENUVERTER_PARAM, -1.0, 1.0, 0));
  266. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(175, 197), module, VoxInhumana::AMP_2_CV_ATTENUVERTER_PARAM, -1.0, 1.0, 0));
  267. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(175, 232), module, VoxInhumana::AMP_3_CV_ATTENUVERTER_PARAM, -1.0, 1.0, 0));
  268. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(175, 267), module, VoxInhumana::AMP_4_CV_ATTENUVERTER_PARAM, -1.0, 1.0, 0));
  269. addParam(ParamWidget::create<RoundSmallBlackKnob>(Vec(175, 302), module, VoxInhumana::AMP_5_CV_ATTENUVERTER_PARAM, -1.0, 1.0, 0));
  270. addInput(Port::create<PJ301MPort>(Vec(13, 62), Port::INPUT, module, VoxInhumana::VOWEL_1_CV_IN));
  271. addInput(Port::create<PJ301MPort>(Vec(143, 62), Port::INPUT, module, VoxInhumana::VOWEL_2_CV_IN));
  272. addInput(Port::create<PJ301MPort>(Vec(80, 62), Port::INPUT, module, VoxInhumana::VOWEL_BALANCE_CV_IN));
  273. addInput(Port::create<PJ301MPort>(Vec(5, 134), Port::INPUT, module, VoxInhumana::VOICE_TYPE_CV_IN));
  274. addInput(Port::create<PJ301MPort>(Vec(170, 97), Port::INPUT, module, VoxInhumana::FC_MAIN_CV_IN));
  275. addInput(Port::create<PJ301MPort>(Vec(50, 162), Port::INPUT, module, VoxInhumana::FREQ_1_CUTOFF_INPUT));
  276. addInput(Port::create<PJ301MPort>(Vec(50, 197), Port::INPUT, module, VoxInhumana::FREQ_2_CUTOFF_INPUT));
  277. addInput(Port::create<PJ301MPort>(Vec(50, 232), Port::INPUT, module, VoxInhumana::FREQ_3_CUTOFF_INPUT));
  278. addInput(Port::create<PJ301MPort>(Vec(50, 267), Port::INPUT, module, VoxInhumana::FREQ_4_CUTOFF_INPUT));
  279. addInput(Port::create<PJ301MPort>(Vec(50, 302), Port::INPUT, module, VoxInhumana::FREQ_5_CUTOFF_INPUT));
  280. addInput(Port::create<PJ301MPort>(Vec(145, 162), Port::INPUT, module, VoxInhumana::AMP_1_INPUT) );
  281. addInput(Port::create<PJ301MPort>(Vec(145, 197), Port::INPUT, module, VoxInhumana::AMP_2_INPUT));
  282. addInput(Port::create<PJ301MPort>(Vec(145, 232), Port::INPUT, module, VoxInhumana::AMP_3_INPUT));
  283. addInput(Port::create<PJ301MPort>(Vec(145, 267), Port::INPUT, module, VoxInhumana::AMP_4_INPUT));
  284. addInput(Port::create<PJ301MPort>(Vec(145, 302), Port::INPUT, module, VoxInhumana::AMP_5_INPUT));
  285. addInput(Port::create<PJ301MPort>(Vec(56, 338), Port::INPUT, module, VoxInhumana::SIGNAL_IN));
  286. addOutput(Port::create<PJ301MPort>(Vec(130, 338), Port::OUTPUT, module, VoxInhumana::VOX_OUTPUT));
  287. addChild(ModuleLightWidget::create<LargeLight<GreenLight>>(Vec(72, 37), module, VoxInhumana::VOWEL_1_LIGHT));
  288. addChild(ModuleLightWidget::create<LargeLight<GreenLight>>(Vec(120, 37), module, VoxInhumana::VOWEL_2_LIGHT));
  289. addChild(Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH-12, 0)));
  290. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH + 12, 0)));
  291. addChild(Widget::create<ScrewSilver>(Vec(RACK_GRID_WIDTH-12, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  292. addChild(Widget::create<ScrewSilver>(Vec(box.size.x - 2 * RACK_GRID_WIDTH + 12, RACK_GRID_HEIGHT - RACK_GRID_WIDTH)));
  293. }
  294. } // namespace rack_plugin_FrozenWasteland
  295. using namespace rack_plugin_FrozenWasteland;
  296. RACK_PLUGIN_MODEL_INIT(FrozenWasteland, VoxInhumana) {
  297. Model *modelVoxInhumana = Model::create<VoxInhumana, VoxInhumanaWidget>("Frozen Wasteland", "VoxInhumana", "Vox Inhumana", FILTER_TAG);
  298. return modelVoxInhumana;
  299. }