ProtoTracer  1.0
Real-time 3D rendering and animation engine
Loading...
Searching...
No Matches
SammyAnimation.h
Go to the documentation of this file.
1#pragma once
2
3#include "../Animation.h"
4#include "../KeyFrameTrack.h"
5#include "../EasyEaseAnimator.h"
6#include "../../Objects/Background.h"
7#include "../../Objects/LEDStripBackground.h"
8#include "../../Morph/NukudeFlat.h"
9#include "../../Render/Scene.h"
10#include "../../Signals/FunctionGenerator.h"
11#include "../../Menu/SingleButtonMenu.h"
12#include "../../Sensors/APDS9960.h"
13
14#include "../../Materials/Animated/RainbowNoise.h"
15#include "../../Materials/Animated/RainbowSpiral.h"
16#include "../../Materials/Animated/SpectrumAnalyzer.h"
17#include "../../Materials/Animated/AudioReactiveGradient.h"
18#include "../../Materials/Animated/Oscilloscope.h"
19
20#include "../../Materials/MaterialAnimator.h"
21
22#include "../AnimationTracks/BlinkTrack.h"
23
24#include "../../Signals/FFTVoiceDetection.h"
25
26#include "../../Sensors/MicrophoneFourier_MAX9814.h"
27
28#include "../../Render/ObjectAlign.h"
29
30#include "../../Screenspace/GlitchX.h"
31#include "../../Screenspace/Fisheye.h"
32#include "../../Screenspace/HorizontalBlur.h"
33#include "../../Screenspace/PhaseOffsetX.h"
34#include "../../Screenspace/PhaseOffsetY.h"
35#include "../../Screenspace/PhaseOffsetR.h"
36#include "../../Screenspace/Magnet.h"
37#include "../../Screenspace/Overflow.h"
38#include "../../Screenspace/RadialBlur.h"
39#include "../../Screenspace/ShiftR.h"
40#include "../../Screenspace/VerticalBlur.h"
41
42class SammyAnimation : public Animation<3> {
43private:
44 static const uint8_t faceCount = 9;
45 NukudeFace pM;
46 Background background;
47 LEDStripBackground ledStripBackground;
48 EasyEaseAnimator<25> eEA = EasyEaseAnimator<25>(EasyEaseInterpolation::Overshoot, 1.0f, 0.35f);
49
50 //Materials
56
57 RGBColor tealPinkSpectrum[2] = {RGBColor(250, 105, 206), RGBColor(5, 225, 245)};
59
60 RGBColor heterochromiaSpectrum[2] = {RGBColor(58, 254, 80), RGBColor(29, 128, 20)};
62
65
66 SpectrumAnalyzer sA = SpectrumAnalyzer(Vector2D(200, 100), Vector2D(100, 50), true, true);
69
70 //Animation controllers
72
79
83
85
87
89
91
92 ObjectAlign objA = ObjectAlign(Vector2D(0.0f, 0.0f), Vector2D(189.0f, 93.0f), Quaternion());
93
105
106 float offsetFace = 0.0f;
107 float offsetFaceSA = 0.0f;
108 float offsetFaceARG = 0.0f;
109 float offsetFaceOSC = 0.0f;
110 uint8_t offsetFaceInd = 50;
111 uint8_t offsetFaceIndSA = 51;
112 uint8_t offsetFaceIndARG = 52;
113 uint8_t offsetFaceIndOSC = 53;
114 bool mirror = false;
115
117 eEA.AddParameter(pM.GetMorphWeightReference(NukudeFace::Anger), NukudeFace::Anger, 15, 0.0f, 1.0f);
118 eEA.AddParameter(pM.GetMorphWeightReference(NukudeFace::Sadness), NukudeFace::Sadness, 50, 0.0f, 1.0f);
119 eEA.AddParameter(pM.GetMorphWeightReference(NukudeFace::Surprised), NukudeFace::Surprised, 10, 0.0f, 1.0f);
120 eEA.AddParameter(pM.GetMorphWeightReference(NukudeFace::Doubt), NukudeFace::Doubt, 25, 0.0f, 1.0f);
121 eEA.AddParameter(pM.GetMorphWeightReference(NukudeFace::Frown), NukudeFace::Frown, 45, 0.0f, 1.0f);
122 eEA.AddParameter(pM.GetMorphWeightReference(NukudeFace::LookUp), NukudeFace::LookUp, 30, 0.0f, 1.0f);
123 eEA.AddParameter(pM.GetMorphWeightReference(NukudeFace::LookDown), NukudeFace::LookDown, 30, 0.0f, 1.0f);
124
125 eEA.AddParameter(pM.GetMorphWeightReference(NukudeFace::vrc_v_ee), NukudeFace::vrc_v_ee, 2, 0.0f, 1.0f);
126 eEA.AddParameter(pM.GetMorphWeightReference(NukudeFace::vrc_v_ih), NukudeFace::vrc_v_ih, 2, 0.0f, 1.0f);
127 eEA.AddParameter(pM.GetMorphWeightReference(NukudeFace::vrc_v_dd), NukudeFace::vrc_v_dd, 2, 0.0f, 1.0f);
128 eEA.AddParameter(pM.GetMorphWeightReference(NukudeFace::vrc_v_rr), NukudeFace::vrc_v_rr, 2, 0.0f, 1.0f);
129 eEA.AddParameter(pM.GetMorphWeightReference(NukudeFace::vrc_v_ch), NukudeFace::vrc_v_ch, 2, 0.0f, 1.0f);
130 eEA.AddParameter(pM.GetMorphWeightReference(NukudeFace::vrc_v_aa), NukudeFace::vrc_v_aa, 2, 0.0f, 1.0f);
131 eEA.AddParameter(pM.GetMorphWeightReference(NukudeFace::vrc_v_oh), NukudeFace::vrc_v_oh, 2, 0.0f, 1.0f);
132 eEA.AddParameter(pM.GetMorphWeightReference(NukudeFace::vrc_v_ss), NukudeFace::vrc_v_ss, 2, 0.0f, 1.0f);
133
134 eEA.AddParameter(pM.GetMorphWeightReference(NukudeFace::HideBlush), NukudeFace::HideBlush, 30, 1.0f, 0.0f);
135 eEA.AddParameter(pM.GetMorphWeightReference(NukudeFace::HideBlush), NukudeFace::HideBlush, 30, 1.0f, 0.0f);
136
137 eEA.AddParameter(&offsetFace, offsetFaceInd, 40, 0.0f, 1.0f);
138 eEA.AddParameter(&offsetFaceSA, offsetFaceIndSA, 40, 0.0f, 1.0f);
141 }
142
144 blink.AddParameter(pM.GetMorphWeightReference(NukudeFace::Blink));
145 }
146
148 eEA.SetInterpolationMethod(NukudeFace::HideBlush, EasyEaseInterpolation::Cosine);
149 eEA.SetInterpolationMethod(NukudeFace::Sadness, EasyEaseInterpolation::Cosine);
150
151 eEA.SetInterpolationMethod(NukudeFace::vrc_v_ee, EasyEaseInterpolation::Linear);
152 eEA.SetInterpolationMethod(NukudeFace::vrc_v_ih, EasyEaseInterpolation::Linear);
153 eEA.SetInterpolationMethod(NukudeFace::vrc_v_dd, EasyEaseInterpolation::Linear);
154 eEA.SetInterpolationMethod(NukudeFace::vrc_v_rr, EasyEaseInterpolation::Linear);
155 eEA.SetInterpolationMethod(NukudeFace::vrc_v_ch, EasyEaseInterpolation::Linear);
156 eEA.SetInterpolationMethod(NukudeFace::vrc_v_aa, EasyEaseInterpolation::Linear);
157 eEA.SetInterpolationMethod(NukudeFace::vrc_v_oh, EasyEaseInterpolation::Linear);
158 eEA.SetInterpolationMethod(NukudeFace::vrc_v_ss, EasyEaseInterpolation::Linear);
159 }
160
176
178 blink.Update();
179 }
180
181 void Default(){
182 scene.DisableEffect();
183 }
184
185 void Angry(){
186 eEA.AddParameterFrame(NukudeFace::Anger, 1.0f);
188 }
189
190 void Sad(){
191 eEA.AddParameterFrame(NukudeFace::Sadness, 1.0f);
192 eEA.AddParameterFrame(NukudeFace::Frown, 1.0f);
194 }
195
196 void Surprised(){
197 scene.SetEffect(&glitchX);
198 scene.DisableEffect();
199
200 eEA.AddParameterFrame(NukudeFace::Surprised, 1.0f);
201 eEA.AddParameterFrame(NukudeFace::HideBlush, 0.0f);
203 }
204
205 void Doubt(){
206 eEA.AddParameterFrame(NukudeFace::Doubt, 1.0f);
207 }
208
209 void Frown(){
210 eEA.AddParameterFrame(NukudeFace::Frown, 1.0f);
211 }
212
213 void LookUp(){
214 eEA.AddParameterFrame(NukudeFace::LookUp, 1.0f);
215 }
216
217 void LookDown(){
218 eEA.AddParameterFrame(NukudeFace::LookDown, 1.0f);
219 }
220
227
234
241
244 eEA.AddParameterFrame(NukudeFace::vrc_v_ss, MicrophoneFourierIT::GetCurrentMagnitude() / 2.0f);
245
246 if(MicrophoneFourierIT::GetCurrentMagnitude() > 0.05f){
247 voiceDetection.Update(MicrophoneFourierIT::GetFourierFiltered(), MicrophoneFourierIT::GetSampleRate());
248
256 }
257 }
258 }
259
261 switch(Menu::GetFaceColor()){
262 case 1: materialAnimator.AddMaterialFrame(warmWhite, 1.0f); break;
263 case 2: materialAnimator.AddMaterialFrame(tealPinkMat, 0.8f); break;
265 case 4: materialAnimator.AddMaterialFrame(rainbowSpiral, 0.3f); break;
266 case 5: materialAnimator.AddMaterialFrame(rainbowSpiral, 0.8f); break;
267 case 6: materialAnimator.AddMaterialFrame(redMaterial, 0.8f); break;
268 case 7: materialAnimator.AddMaterialFrame(blueMaterial, 0.8f); break;
269 case 8: materialAnimator.AddMaterialFrame(rainbowSpiral, 0.8f); break;
270 case 9: materialAnimator.AddMaterialFrame(rainbowNoise, 0.8f); break;
271 default: break;
272 }
273 }
274
275public:
277 scene.AddObject(pM.GetObject());
278 scene.AddObject(background.GetObject());
279 scene.AddObject(ledStripBackground.GetObject());
280
281 LinkEasyEase();
283
285
287
288 pM.GetObject()->SetMaterial(&materialAnimator);
289 background.GetObject()->SetMaterial(&backgroundMaterial);
290 ledStripBackground.GetObject()->SetMaterial(&materialAnimator);
291
292 boop.Initialize(5);
293
294 MicrophoneFourierIT::Initialize(22, 8000, 50.0f, 120.0f);//8KHz sample rate, 50dB min, 120dB max
295 //Menu::Initialize(9);//NeoTrellis
296 Menu::Initialize(9, 0, 500);//7 is number of faces
297
299 objA.SetMirrorX(true);
300 }
301
304 }
305
306 uint8_t GetBrightness(){
307 return Menu::GetBrightness();
308 }
309
310 void FadeIn(float stepRatio) override {}
311 void FadeOut(float stepRatio) override {}
312
314 return pM.GetObject();
315 }
316
318 this->mirror = mirror;
319 }
320
321 void Update(float ratio) override {
322 if(!mirror){
323 heterochromiaSpectrum[0].SetColor(0, 191, 255);
324 heterochromiaSpectrum[1].SetColor(0, 191, 255);
326
327 pM.Reset();
328
329 float xOffset = fGenMatXMove.Update();
330 float yOffset = fGenMatYMove.Update();
331
332 Menu::Update(ratio);
333
334 //Menu::SetSize(Vector2D(280, 60));
335 //Menu::SetPositionOffset(Vector2D(0.0f, -30.0f * yOffset));
336
337 //glitchX.SetRatio(fGenBlur.Update());
338 magnet.SetRatio(ratio);
347
349
350 bool isBooped = Menu::UseBoopSensor() ? boop.isBooped() : 0;
351 uint8_t mode = Menu::GetFaceState();//change by button press
352
353 MicrophoneFourierIT::Update();
354 sA.SetHueAngle(ratio * 360.0f * 4.0f);
357
358 aRG.SetRadius((xOffset + 2.0f) * 2.0f + 25.0f);
359 aRG.SetSize(Vector2D((xOffset + 2.0f) * 10.0f + 50.0f, (xOffset + 2.0f) * 10.0f + 50.0f));
360 aRG.SetHueAngle(ratio * 360.0f * 8.0f);
361 aRG.SetRotation(ratio * 360.0f * 2.0f);
362 aRG.SetPosition(Vector2D(80.0f + xOffset * 4.0f, 48.0f + yOffset * 4.0f));
363
364 oSC.SetSize(Vector2D(200.0f, 100.0f));
365 oSC.SetHueAngle(ratio * 360.0f * 8.0f);
366 oSC.SetPosition(Vector2D(100.0f, 50.0f));
367
368 voiceDetection.SetThreshold(map(Menu::GetMicLevel(), 0, 10, 1000, 50));
369
371
372 if (isBooped && mode != 6){
373 Surprised();
374 }
375 else{
376 if (mode == 0) Default();
377 else if (mode == 1) Angry();
378 else if (mode == 2) Doubt();
379 else if (mode == 3) Frown();
380 else if (mode == 4) LookUp();
381 else if (mode == 5) Sad();
382 else if (mode == 6) {
383 aRG.Update(MicrophoneFourierIT::GetFourierFiltered());
385 }
386 else if (mode == 7){
387 oSC.Update(MicrophoneFourierIT::GetSamples());
389 }
390 else {
391 sA.Update(MicrophoneFourierIT::GetFourierFiltered());
393 }
394 }
395
397
398 pM.SetMorphWeight(NukudeFace::BiggerNose, 1.0f);
399 pM.SetMorphWeight(NukudeFace::MoveEye, 1.0f);
400
401 eEA.Update();
402 pM.Update();
403
404 //phaseR.SetRatio(eEA.GetValue(NukudeFace::Surprised));
405 //glitchX.SetRatio(eEA.GetValue(NukudeFace::Surprised));
406
407 rainbowNoise.Update(ratio);
411
412 uint8_t faceSize = Menu::GetFaceSize();
413 float scale = Menu::ShowMenu() * 0.6f + 0.4f;
414 float faceSizeOffset = faceSize * 8.0f;
415
417 objA.SetEdgeMargin(4.0f);
418 objA.SetCameraMax(Vector2D(110.0f + faceSizeOffset, 115.0f - 115.0f * offsetFace).Multiply(scale));
419
420 objA.AlignObjects(scene.GetObjects(), 1);
421
422 pM.GetObject()->GetTransform()->SetPosition(Vector3D(xOffset, yOffset, 0.0f));
423 pM.GetObject()->UpdateTransform();
424 }
425 else{
426 heterochromiaSpectrum[0].SetColor(255, 165, 0);
427 heterochromiaSpectrum[1].SetColor(255, 165, 0);
429 }
430 }
431};
A class for managing the Adafruit APDS9960 sensor.
Definition APDS9960.h:27
static bool Initialize(uint8_t threshold)
Initializes the APDS9960 sensor.
Definition APDS9960.cpp:14
static bool isBooped()
Checks if the sensor is "booped" (close proximity detected).
Definition APDS9960.cpp:43
void AddParameter(float *parameter)
Adds a parameter to the animation track.
float Update()
Updates the animation track and returns the current parameter value.
A material class for creating an audio-reactive gradient effect.
void SetRadius(float radius)
Sets the radius for circular gradient patterns.
void SetPosition(Vector2D offset)
Sets the position of the gradient.
void Update(float *readData)
Updates the gradient based on new audio data.
void SetSize(Vector2D size)
Sets the size of the gradient.
void SetRotation(float angle)
Sets the rotation angle of the gradient.
void SetHueAngle(float hueAngle)
Sets the hue angle for color adjustments.
A template class for animating eye blinking using keyframes.
Definition BlinkTrack.h:27
A template class for implementing advanced animation easing.
void AddParameterFrame(uint16_t dictionaryValue, float value) override
Adds a single frame value for a parameter.
void Update() override
Updates the animator, advancing all animations.
void SetInterpolationMethod(uint16_t dictionaryValue, InterpolationMethod interpMethod) override
Sets the interpolation method for a specific parameter.
void AddParameter(float *parameter, uint16_t dictionaryValue, uint16_t frames, float basis, float goal) override
Adds a parameter to the animator.
void SetRatio(float ratio)
Sets the scaling ratio for the effect.
Definition Effect.cpp:5
Detects visemes based on FFT voice analysis.
float GetViseme(MouthShape viseme)
Retrieves the probability of a specific viseme.
void SetThreshold(float threshold)
Sets the threshold for formant calculations.
void Update(float *peaks, float maxFrequency)
Updates the viseme probabilities based on new FFT data.
Implements a fisheye distortion effect for pixel groups.
Definition Fisheye.h:26
A class to generate various waveform functions with customizable parameters.
@ Sawtooth
Sawtooth waveform.
@ Sine
Sine waveform.
@ Triangle
Triangle waveform.
float Update()
Updates and calculates the next value of the waveform.
Implements a glitch effect along the X-axis for pixel groups.
Definition GlitchX.h:26
Creates a customizable gradient material for rendering.
void UpdateRGB()
Updates the RGB colors in the gradient.
Implements a horizontal blur effect for pixel groups.
Implements a magnetic distortion effect for pixel groups.
Definition Magnet.h:25
Animates transitions and blends between multiple materials.
void AddMaterial(Material::Method method, Material *material, uint16_t frames, float minOpacity, float maxOpacity)
Adds a material to the animation with specified properties.
void SetBaseMaterial(Material::Method method, Material *material)
Sets the base material for the animation.
void AddMaterialFrame(Material &material, float opacity)
Adds a specific frame for a material in the animation.
void Update()
Updates the animator, advancing the transitions.
@ Add
Adds colors together.
Definition Material.h:35
@ Replace
Replaces the base color.
Definition Material.h:44
static uint8_t GetFaceState()
Retrieves the current face state. In hardware mode, it is read from the MenuHandler.
Definition Menu.cpp:381
static uint8_t GetFaceColor()
Gets the current face color index.
Definition Menu.cpp:453
static uint8_t GetMicLevel()
Gets the current microphone level.
Definition Menu.cpp:417
static float ShowMenu()
Returns how much of the menu is shown, typically normalized (0.0 to 1.0).
Definition Menu.cpp:494
static Material * GetMaterial()
Provides a pointer to the material used for rendering the menu text.
Definition Menu.cpp:155
static uint8_t MirrorSpectrumAnalyzer()
Checks if the spectrum analyzer mirroring is toggled on or off.
Definition Menu.cpp:435
static uint8_t GetFaceSize()
Gets the current face size.
Definition Menu.cpp:444
static void Initialize(uint8_t faceCount, uint8_t pin, uint16_t holdingTime, Vector2D size=Vector2D(240, 50))
Initializes the Menu using a face count, input pin, holding time, and size.
Definition Menu.cpp:102
static uint8_t UseMicrophone()
Checks if the microphone usage is toggled on or off.
Definition Menu.cpp:408
static uint8_t UseBoopSensor()
Checks if the boop sensor usage is toggled on or off.
Definition Menu.cpp:426
static void Update(float ratio)
Updates the menu each frame, handling transitions, wiggle effects, and text generation.
Definition Menu.cpp:208
static uint8_t GetBrightness()
Gets the current brightness level. In hardware mode, it is read from the MenuHandler.
Definition Menu.cpp:390
static uint8_t GetAccentBrightness()
Gets the current accent brightness level.
Definition Menu.cpp:399
Represents a 3D object with geometry, material, and transformation data.
Definition Object3D.h:28
Handles aligning and transforming 3D objects to fit within specified 2D camera bounds.
Definition ObjectAlign.h:24
void SetEdgeMargin(float edgeMargin)
Sets the margin to keep from the edges when aligning objects.
@ Stretch
Attempt to scale the object(s) to fill the entire area.
Definition ObjectAlign.h:43
void SetJustification(Justification jst)
Sets the justification mode for alignment.
void SetPlaneOffsetAngle(float offsetPlaneAngle)
Sets the additional rotation offset (plane offset angle), in degrees or radians, that will be applied...
void SetCameraMax(Vector2D camMax)
Updates the maximum bounds for the 2D camera region.
void AlignObjects(Object3D **objs, uint8_t numObjects)
Aligns multiple objects within the camera bounds, including scale factors.
void SetMirrorX(bool mirrorX)
Enables or disables mirroring along the X-axis for the aligned objects.
A dynamic oscilloscope material for visualizing audio signals.
void SetPosition(Vector2D offset)
Sets the position of the oscilloscope visualization.
void SetSize(Vector2D size)
Sets the size of the oscilloscope visualization.
void Update(float *data)
Updates the oscilloscope visualization based on new audio data.
void SetHueAngle(float hueAngle)
Sets the hue angle for color adjustments.
Implements an overflow distortion effect for pixel groups.
Definition Overflow.h:24
Applies rotational phase offsets to pixel groups.
Applies horizontal phase offsets to pixel groups.
Applies vertical phase offsets to pixel groups.
A mathematical construct representing a rotation in 3D space.
Definition Quaternion.h:30
Represents an RGB color and provides methods for manipulation.
Definition RGBColor.h:23
void SetColor(const uint8_t &R, const uint8_t &G, const uint8_t &B)
Sets the RGB values of the color.
Definition RGBColor.cpp:23
Applies a radial blur effect to pixel groups.
Definition RadialBlur.h:26
A dynamic material that creates a rainbow effect using simplex noise.
void Update(float ratio)
Updates the material animation based on the time ratio.
A dynamic material creating a colorful rainbow spiral animation.
void Update(float ratio)
Updates the material animation based on the time ratio.
FunctionGenerator fGenMatHue
FunctionGenerator fGenMatYMove
SpectrumAnalyzer sA
Oscilloscope oSC
SimpleMaterial redMaterial
void UpdateKeyFrameTracks()
PhaseOffsetR phaseR
RainbowSpiral rainbowSpiral
SimpleMaterial blueMaterial
FunctionGenerator fGenMatRMenu
PhaseOffsetX phaseX
void AudioReactiveGradientFace()
GradientMaterial< 2 > tealPinkMat
VerticalBlur blurV
EasyEaseAnimator< 25 > eEA
BlinkTrack< 1 > blink
LEDStripBackground ledStripBackground
void ChangeInterpolationMethods()
RadialBlur blurR
RGBColor tealPinkSpectrum[2]
FunctionGenerator fGenSpiral
void SpectrumAnalyzerFace()
FunctionGenerator fGenMatPos
FunctionGenerator fGenScale
Background background
FunctionGenerator fGenRotation
FunctionGenerator fGenMatXMenu
PhaseOffsetY phaseY
void SetCameraMirror(bool mirror)
void FadeIn(float stepRatio) override
void FadeOut(float stepRatio) override
RainbowNoise rainbowNoise
FunctionGenerator fGenMatYMenu
FunctionGenerator fGenMatXMove
MaterialAnimator< 10 > materialAnimator
void Update(float ratio) override
ObjectAlign objA
uint8_t offsetFaceIndSA
static const uint8_t faceCount
GradientMaterial< 2 > heterochromiaMat
RGBColor heterochromiaSpectrum[2]
FFTVoiceDetection< 128 > voiceDetection
FunctionGenerator fGenBlur
MaterialAnimator< 4 > backgroundMaterial
uint8_t offsetFaceIndOSC
HorizontalBlur blurH
uint8_t GetBrightness()
SimpleMaterial warmWhite
uint8_t GetAccentBrightness()
Object3D * GetObject()
uint8_t offsetFaceIndARG
AudioReactiveGradient aRG
Radially shifts the red, green, and blue channels of the pixels.
Definition ShiftR.h:26
A material that applies a single, solid RGB color to surfaces.
A material that visualizes audio data as a spectrum.
void SetMirrorYState(bool state)
Sets the mirroring state for the visualization.
void Update(float *readData)
Updates the spectrum visualization with new audio data.
void SetFlipYState(bool state)
Sets the flipping state for the visualization.
void SetHueAngle(float hueAngle)
Sets the hue adjustment angle for the spectrum colors.
Represents a 2D vector (X, Y) and provides methods for vector arithmetic.
Definition Vector2D.h:27
Represents a 3D vector (X, Y, Z) and provides methods for vector arithmetic.
Definition Vector3D.h:26
An effect that applies a vertical blur to a pixel group.
@ ER
Mouth shape corresponding to the "ER" sound.
@ OO
Mouth shape corresponding to the "OO" sound.
@ AH
Mouth shape corresponding to the "AH" sound.
@ UH
Mouth shape corresponding to the "UH" sound.
@ AR
Mouth shape corresponding to the "AR" sound.
@ EE
Mouth shape corresponding to the "EE" sound.