This commit is contained in:
thomas committed 2026-10-18 23:39:44 +02:00
1 parent 2b9e574ba9
commit b119a6abd7
583 files changed
+224175 -218466

No files matched your search

@@ -0,0 +1,53 @@
#ifndef EFFECTCARD_HPP
#define EFFECTCARD_HPP
#include <gui/common/UiTheme.hpp>
#include <touchgfx/Callback.hpp>
#include <touchgfx/events/ClickEvent.hpp>
#include <touchgfx/widgets/BoxWithBorder.hpp>
/* Carte d'effet de l'ecran d'accueil :
* - appui n'importe ou sur la carte -> callback "open" (ouvre l'ecran de reglage)
* - appui sur l'interrupteur en bas a droite -> active/bypass l'effet sans quitter l'accueil
* L'etat est lu/ecrit directement dans le booleen "enabled" de l'effet
* (AudioEffectsParams), comme le font les ecrans de reglage. */
class EffectCard : public touchgfx::Container
{
public:
static const int16_t WIDTH = 244;
static const int16_t HEIGHT = 130;
EffectCard();
void setup(ui::Effect effect, TEXTS title, TEXTS description, bool* enabled,
touchgfx::GenericCallback<const EffectCard&>& openCallback);
ui::Effect getEffect() const
{
return effect;
}
/* Relit l'etat de l'effet et met a jour l'affichage */
void refresh();
virtual void handleClickEvent(const touchgfx::ClickEvent& event);
private:
bool isInSwitchArea(int16_t x, int16_t y) const;
void setPressed(bool pressed);
ui::Effect effect;
bool* enabled;
touchgfx::GenericCallback<const EffectCard&>* openAction;
bool pressedOnSwitch;
touchgfx::BoxWithBorder background;
touchgfx::Box accentBar;
touchgfx::TextArea title;
touchgfx::TextArea description;
touchgfx::TextArea status;
touchgfx::BoxWithBorder switchTrack;
touchgfx::Box switchKnob;
};
#endif // EFFECTCARD_HPP
@@ -0,0 +1,149 @@
#ifndef UITHEME_HPP
#define UITHEME_HPP
/* Charte graphique commune a tous les ecrans (code utilisateur, independant de
* TouchGFX Designer) : couleurs, geometrie de l'en-tete et petits widgets
* reutilisables. Les ecrans generes par Designer sont re-agences dans les
* setupScreen() des vues a partir de ces constantes. */
#include <touchgfx/Color.hpp>
#include <touchgfx/Unicode.hpp>
#include <touchgfx/containers/Container.hpp>
#include <touchgfx/widgets/Box.hpp>
#include <touchgfx/widgets/ButtonWithLabel.hpp>
#include <touchgfx/containers/Slider.hpp>
#include <touchgfx/widgets/TextArea.hpp>
#include <touchgfx/widgets/TextAreaWithWildcard.hpp>
#include <touchgfx/widgets/ToggleButton.hpp>
#include <texts/TextKeysAndLanguages.hpp>
namespace ui
{
inline touchgfx::colortype rgb(uint8_t r, uint8_t g, uint8_t b)
{
return touchgfx::Color::getColorFromRGB(r, g, b);
}
/* Palette "horlogerie" : fond brun tres sombre, texte creme */
inline touchgfx::colortype textPrimary() { return rgb(230, 214, 170); }
inline touchgfx::colortype textMuted() { return rgb(150, 136, 108); }
inline touchgfx::colortype surface() { return rgb(30, 22, 15); }
inline touchgfx::colortype surfacePressed(){ return rgb(58, 44, 30); }
inline touchgfx::colortype surfaceBorder() { return rgb(82, 64, 42); }
inline touchgfx::colortype headerBg() { return rgb(18, 13, 9); }
inline touchgfx::colortype switchOff() { return rgb(70, 60, 48); }
/* Une couleur d'accent par effet, reprise sur la carte d'accueil et l'ecran de reglage */
enum Effect
{
EFFECT_OCTAVER,
EFFECT_EQUALIZER,
EFFECT_OVERDRIVE,
EFFECT_SATURATION,
EFFECT_ECHO,
EFFECT_REVERB,
EFFECT_SPECTRUM,
EFFECT_COUNT
};
inline touchgfx::colortype accent(Effect e)
{
switch (e)
{
case EFFECT_OCTAVER: return rgb(232, 96, 92);
case EFFECT_EQUALIZER: return rgb(112, 200, 122);
case EFFECT_OVERDRIVE: return rgb(242, 152, 44);
case EFFECT_SATURATION: return rgb(230, 122, 188);
case EFFECT_ECHO: return rgb(92, 162, 240);
case EFFECT_REVERB: return rgb(170, 124, 240);
default: return textPrimary();
}
}
/* Geometrie de l'ecran (800x480) */
static const int16_t SCREEN_W = 800;
static const int16_t SCREEN_H = 480;
static const int16_t HEADER_H = 80;
/* Bandeau d'en-tete : fond sombre + liseré de la couleur de l'effet */
class Header : public touchgfx::Container
{
public:
Header()
{
setPosition(0, 0, SCREEN_W, HEADER_H + 3);
bar.setPosition(0, 0, SCREEN_W, HEADER_H);
bar.setColor(headerBg());
bar.setAlpha(235);
add(bar);
line.setPosition(0, HEADER_H, SCREEN_W, 3);
add(line);
}
void setAccent(touchgfx::colortype c)
{
line.setColor(c);
}
private:
touchgfx::Box bar;
touchgfx::Box line;
};
/* Zone de texte affichant une valeur formatee ("75 %", "350 ms", "+6 dB"...) */
class ValueText : public touchgfx::TextAreaWithOneWildcard
{
public:
ValueText()
{
buffer[0] = 0;
setWildcard(buffer);
}
void init(touchgfx::TypedText text, touchgfx::colortype color, int16_t x, int16_t y, int16_t w, int16_t h)
{
setTypedText(text);
setColor(color);
setPosition(x, y, w, h);
}
void show(const char* format, int value)
{
touchgfx::Unicode::snprintf(buffer, SIZE, format, value);
invalidate();
}
/* Gain signe avec signe explicite : "+6 dB" / "-12 dB" / "0 dB" */
void showDb(int value)
{
show(value > 0 ? "+%d dB" : "%d dB", value);
}
private:
static const uint16_t SIZE = 16;
touchgfx::Unicode::UnicodeChar buffer[SIZE];
};
/* Mise en page commune des ecrans d'effet generes par Designer :
* en-tete (retour a gauche, titre centre, marche/arret a droite).
* La vue doit inserer "header" juste au-dessus du fond (insert(&box1, header)). */
inline void layoutEffectHeader(Header& header,
touchgfx::colortype accentColor, touchgfx::ButtonWithLabel& back,
touchgfx::TextArea& title, touchgfx::ToggleButton& toggle)
{
header.setAccent(accentColor);
back.setXY(0, -7); /* bouton 225x94, partie visible ~50 px centree */
title.setPosition(225, 17, SCREEN_W - 2 * 225, 46);
title.setColor(textPrimary());
toggle.setXY(SCREEN_W - 170 - 16, 10); /* toggle 170x60 */
}
/* Ligne de reglage horizontale : libelle a gauche, curseur, valeur a droite */
inline void layoutParamRow(touchgfx::TextArea& label, touchgfx::Slider& slider, ValueText& value,
touchgfx::colortype accentColor, int16_t y)
{
label.setPosition(32, y + 14, 150, 26);
label.setColor(textMuted());
slider.setXY(184, y); /* curseur 456x52 */
value.init(touchgfx::TypedText(T_VALUE_M_LEFT), accentColor, 656, y + 10, 136, 34);
}
} // namespace ui
#endif // UITHEME_HPP
@@ -3,6 +3,7 @@
#include <gui_generated/echo_screen/EchoViewBase.hpp>
#include <gui/echo_screen/EchoPresenter.hpp>
#include <gui/common/UiTheme.hpp>
class EchoView : public EchoViewBase
{
@@ -17,6 +18,8 @@ public:
virtual void sliderFeedbackChanged(int value);
virtual void sliderMixChanged(int value);
protected:
ui::Header header;
ui::ValueText values[3];
};
#endif // ECHOVIEW_HPP
@@ -3,6 +3,7 @@
#include <gui_generated/equalizer_screen/EqualizerViewBase.hpp>
#include <gui/equalizer_screen/EqualizerPresenter.hpp>
#include <gui/common/UiTheme.hpp>
class EqualizerView : public EqualizerViewBase
{
@@ -24,6 +25,11 @@ public:
virtual void sliderBand9Changed(int value);
virtual void sliderBand10Changed(int value);
protected:
ui::Header header;
ui::ValueText values[10];
touchgfx::Box zeroDbLine;
void setBand(int index, int value);
};
#endif // EQUALIZERVIEW_HPP
@@ -1,17 +1,20 @@
#ifndef INITSCREENVIEW_HPP
#define INITSCREENVIEW_HPP
#include <gui_generated/initscreen_screen/InitScreenViewBase.hpp>
#include <gui/initscreen_screen/InitScreenPresenter.hpp>
class InitScreenView : public InitScreenViewBase
{
public:
InitScreenView();
virtual ~InitScreenView() {}
virtual void setupScreen();
virtual void tearDownScreen();
protected:
};
#endif // INITSCREENVIEW_HPP
#ifndef INITSCREENVIEW_HPP
#define INITSCREENVIEW_HPP
#include <gui_generated/initscreen_screen/InitScreenViewBase.hpp>
#include <gui/initscreen_screen/InitScreenPresenter.hpp>
#include <touchgfx/widgets/TextArea.hpp>
class InitScreenView : public InitScreenViewBase
{
public:
InitScreenView();
virtual ~InitScreenView() {}
virtual void setupScreen();
virtual void tearDownScreen();
protected:
touchgfx::TextArea title;
touchgfx::TextArea hint;
};
#endif // INITSCREENVIEW_HPP
@@ -3,6 +3,7 @@
#include <gui_generated/octaver_screen/OctaverViewBase.hpp>
#include <gui/octaver_screen/OctaverPresenter.hpp>
#include <gui/common/UiTheme.hpp>
class OctaverView : public OctaverViewBase
{
@@ -19,6 +20,10 @@ public:
virtual void slider4Clicked(int value);
virtual void slider5Clicked(int value);
protected:
ui::Header header;
ui::ValueText values[5];
void showLevel(int index, int value);
};
#endif // OCTAVERVIEW_HPP
@@ -3,6 +3,7 @@
#include <gui_generated/oscillo_screen/OscilloViewBase.hpp>
#include <gui/oscillo_screen/OscilloPresenter.hpp>
#include <gui/common/UiTheme.hpp>
class OscilloView : public OscilloViewBase
{
@@ -15,6 +16,7 @@ public:
virtual void toggleClicked();
protected:
ui::Header header;
};
#endif // OSCILLOVIEW_HPP
@@ -3,6 +3,7 @@
#include <gui_generated/overdrive_screen/OverdriveViewBase.hpp>
#include <gui/overdrive_screen/OverdrivePresenter.hpp>
#include <gui/common/UiTheme.hpp>
class OverdriveView : public OverdriveViewBase
{
@@ -17,6 +18,8 @@ public:
virtual void sliderToneChanged(int value);
virtual void sliderLevelChanged(int value);
protected:
ui::Header header;
ui::ValueText values[3];
};
#endif // OVERDRIVEVIEW_HPP
@@ -1,22 +1,60 @@
#ifndef OVERVIEWVIEW_HPP
#define OVERVIEWVIEW_HPP
#include <gui_generated/overview_screen/OverviewViewBase.hpp>
#include <gui/overview_screen/OverviewPresenter.hpp>
class OverviewView : public OverviewViewBase
{
public:
OverviewView();
virtual ~OverviewView() {}
virtual void setupScreen();
virtual void tearDownScreen();
virtual void handleTickEvent();
virtual void toggleAudioOnOFF();
virtual void slider1Changed(int value);
protected:
bool repeatButtonWasPressed;
};
#endif // OVERVIEWVIEW_HPP
#ifndef OVERVIEWVIEW_HPP
#define OVERVIEWVIEW_HPP
#include <gui_generated/overview_screen/OverviewViewBase.hpp>
#include <gui/overview_screen/OverviewPresenter.hpp>
#include <gui/common/EffectCard.hpp>
#include <gui/common/UiTheme.hpp>
#include <touchgfx/widgets/canvas/Circle.hpp>
#include <touchgfx/widgets/canvas/PainterRGB565.hpp>
/* Ecran d'accueil : marche/arret + volume en haut, grille des 6 effets
* (ouvrir / activer), looper et spectre en bas.
* Les boutons d'effet generes par Designer (buttonWithLabel1..6) sont masques et
* remplaces par des EffectCard ; le reste des widgets generes est re-agence. */
class OverviewView : public OverviewViewBase
{
public:
OverviewView();
virtual ~OverviewView();
virtual void setupScreen();
virtual void tearDownScreen();
virtual void handleTickEvent();
virtual void toggleAudioOnOFF();
virtual void slider1Changed(int value);
protected:
enum LooperState
{
LOOPER_IDLE,
LOOPER_RECORDING,
LOOPER_PLAYING
};
void onCardOpen(const EffectCard& card);
void setLooperState(LooperState state);
/* Buffer du CanvasWidgetRenderer (voyant du looper), propre a cet ecran comme
* celui genere pour Oscillo */
static const uint32_t CANVAS_BUFFER_SIZE = 2400;
uint8_t canvasBuffer[CANVAS_BUFFER_SIZE];
ui::Header header;
EffectCard cards[6];
ui::ValueText volumeValue;
touchgfx::TextArea looperTitle;
touchgfx::TextArea looperStatus;
touchgfx::Circle recDot;
touchgfx::PainterRGB565 recDotPainter;
touchgfx::Callback<OverviewView, const EffectCard&> cardOpenCallback;
bool repeatButtonWasPressed;
LooperState looperState;
uint32_t looperTicks; /* duree de l'enregistrement en cours, en ticks IHM */
uint32_t playTicksLeft; /* estimation de la lecture restante */
};
#endif // OVERVIEWVIEW_HPP
@@ -3,6 +3,7 @@
#include <gui_generated/reverb_screen/ReverbViewBase.hpp>
#include <gui/reverb_screen/ReverbPresenter.hpp>
#include <gui/common/UiTheme.hpp>
class ReverbView : public ReverbViewBase
{
@@ -17,6 +18,8 @@ public:
virtual void sliderAmortiChanged(int value);
virtual void sliderMixChanged(int value);
protected:
ui::Header header;
ui::ValueText values[3];
};
#endif // REVERBVIEW_HPP
@@ -3,6 +3,7 @@
#include <gui_generated/saturation_screen/SaturationViewBase.hpp>
#include <gui/saturation_screen/SaturationPresenter.hpp>
#include <gui/common/UiTheme.hpp>
class SaturationView : public SaturationViewBase
{
@@ -16,6 +17,8 @@ public:
virtual void sliderDriveClicked(int value);
virtual void sliderLevelClicked(int value);
protected:
ui::Header header;
ui::ValueText values[2];
};
#endif // SATURATIONVIEW_HPP
@@ -0,0 +1,136 @@
#include <gui/common/EffectCard.hpp>
namespace
{
const int16_t SWITCH_W = 62;
const int16_t SWITCH_H = 32;
const int16_t KNOB = 24;
const int16_t SWITCH_X = EffectCard::WIDTH - SWITCH_W - 16;
const int16_t SWITCH_Y = EffectCard::HEIGHT - SWITCH_H - 14;
/* Zone tactile de l'interrupteur, volontairement plus large que le dessin */
const int16_t SWITCH_HIT_W = 112;
const int16_t SWITCH_HIT_H = 66;
}
EffectCard::EffectCard()
: effect(ui::EFFECT_OCTAVER),
enabled(0),
openAction(0),
pressedOnSwitch(false)
{
setWidthHeight(WIDTH, HEIGHT);
setTouchable(true);
background.setPosition(0, 0, WIDTH, HEIGHT);
background.setColor(ui::surface());
background.setBorderColor(ui::surfaceBorder());
background.setBorderSize(1);
background.setAlpha(225);
add(background);
accentBar.setPosition(0, 0, 6, HEIGHT);
add(accentBar);
title.setPosition(22, 14, WIDTH - 30, 34);
title.setColor(ui::textPrimary());
add(title);
description.setPosition(22, 50, WIDTH - 30, 24);
description.setColor(ui::textMuted());
add(description);
status.setPosition(22, SWITCH_Y + 4, 60, 24);
add(status);
switchTrack.setPosition(SWITCH_X, SWITCH_Y, SWITCH_W, SWITCH_H);
switchTrack.setBorderSize(2);
add(switchTrack);
switchKnob.setWidthHeight(KNOB, KNOB);
switchKnob.setColor(ui::textPrimary());
add(switchKnob);
}
void EffectCard::setup(ui::Effect e, TEXTS titleText, TEXTS descriptionText, bool* enabledFlag,
touchgfx::GenericCallback<const EffectCard&>& openCallback)
{
effect = e;
enabled = enabledFlag;
openAction = &openCallback;
title.setTypedText(touchgfx::TypedText(titleText));
description.setTypedText(touchgfx::TypedText(descriptionText));
refresh();
}
void EffectCard::refresh()
{
const bool on = enabled && *enabled;
const touchgfx::colortype accentColor = ui::accent(effect);
accentBar.setColor(on ? accentColor : ui::switchOff());
status.setTypedText(touchgfx::TypedText(on ? T_ON : T_OFF));
status.setColor(on ? accentColor : ui::textMuted());
switchTrack.setColor(on ? accentColor : ui::switchOff());
switchTrack.setBorderColor(on ? accentColor : ui::surfaceBorder());
const int16_t knobX = on ? SWITCH_X + SWITCH_W - KNOB - 4 : SWITCH_X + 4;
switchKnob.setXY(knobX, SWITCH_Y + (SWITCH_H - KNOB) / 2);
switchKnob.setColor(on ? ui::rgb(255, 255, 255) : ui::textMuted());
invalidate();
}
bool EffectCard::isInSwitchArea(int16_t x, int16_t y) const
{
return x >= WIDTH - SWITCH_HIT_W && y >= HEIGHT - SWITCH_HIT_H;
}
void EffectCard::setPressed(bool pressed)
{
background.setColor(pressed ? ui::surfacePressed() : ui::surface());
background.invalidate();
}
void EffectCard::handleClickEvent(const touchgfx::ClickEvent& event)
{
const int16_t x = event.getX();
const int16_t y = event.getY();
switch (event.getType())
{
case touchgfx::ClickEvent::PRESSED:
pressedOnSwitch = isInSwitchArea(x, y);
if (!pressedOnSwitch)
{
setPressed(true);
}
break;
case touchgfx::ClickEvent::RELEASED:
setPressed(false);
/* Relachement hors de la carte = annulation */
if (x < 0 || y < 0 || x >= WIDTH || y >= HEIGHT)
{
break;
}
if (pressedOnSwitch)
{
if (isInSwitchArea(x, y) && enabled)
{
*enabled = !*enabled;
refresh();
}
}
else if (openAction && openAction->isValid())
{
openAction->execute(*this);
}
break;
case touchgfx::ClickEvent::CANCEL:
default:
setPressed(false);
break;
}
}
@@ -8,10 +8,26 @@ EchoView::EchoView()
void EchoView::setupScreen()
{
EchoViewBase::setupScreen();
toggleButton1.forceState(AudioEffects_GetParams()->echo.enabled);
slider1.setValue((int16_t)(AudioEffects_GetParams()->echo.delay_ms / 10.0f));
slider2.setValue((int16_t)(AudioEffects_GetParams()->echo.feedback / 0.95f * 100.0f));
slider3.setValue((int16_t)(AudioEffects_GetParams()->echo.mix * 100.0f));
const touchgfx::colortype accent = ui::accent(ui::EFFECT_ECHO);
insert(&box1, header);
ui::layoutEffectHeader(header, accent, buttonWithLabel1, textArea1, toggleButton1);
ui::layoutParamRow(textArea2, slider1, values[0], accent, 120);
ui::layoutParamRow(textArea2_1, slider2, values[1], accent, 230);
ui::layoutParamRow(textArea2_2, slider3, values[2], accent, 340);
for (int i = 0; i < 3; i++)
{
add(values[i]);
}
FxEchoParams& p = AudioEffects_GetParams()->echo;
toggleButton1.forceState(p.enabled);
slider1.setValue((int16_t)(p.delay_ms / 10.0f + 0.5f));
slider2.setValue((int16_t)(p.feedback / 0.95f * 100.0f + 0.5f));
slider3.setValue((int16_t)(p.mix * 100.0f + 0.5f));
values[0].show("%d ms", slider1.getValue() * 10);
values[1].show("%d %%", slider2.getValue());
values[2].show("%d %%", slider3.getValue());
}
void EchoView::tearDownScreen()
@@ -27,12 +43,15 @@ void EchoView::toggleClicked()
void EchoView::sliderDelaiChanged(int value)
{
AudioEffects_GetParams()->echo.delay_ms = value * 10.0f;
values[0].show("%d ms", value * 10);
}
void EchoView::sliderFeedbackChanged(int value)
{
AudioEffects_GetParams()->echo.feedback = value / 100.0f * 0.95f;
values[1].show("%d %%", value);
}
void EchoView::sliderMixChanged(int value)
{
AudioEffects_GetParams()->echo.mix = value / 100.0f;
values[2].show("%d %%", value);
}
@@ -1,6 +1,26 @@
#include <gui/equalizer_screen/EqualizerView.hpp>
#include <audio_effects.h>
namespace
{
/* 10 bandes regulierement espacees : gain en haut, curseur (56x352), frequence en bas */
const int16_t BAND_X0 = 22;
const int16_t BAND_STEP = 76;
const int16_t VALUE_Y = ui::HEADER_H + 6;
const int16_t SLIDER_Y = ui::HEADER_H + 26;
const int16_t LABEL_Y = 454;
/* Piste du curseur vertical : 300 px a partir de y+26 -> 0 dB au milieu */
const int16_t ZERO_DB_Y = SLIDER_Y + 26 + 150;
const float GAIN_RANGE_DB = 48.0f; /* -24..+24 dB sur 0..100 */
int sliderToDb(int value)
{
const float db = value / 100.0f * GAIN_RANGE_DB - GAIN_RANGE_DB / 2.0f;
return (int)(db + (db >= 0.0f ? 0.5f : -0.5f));
}
}
EqualizerView::EqualizerView()
{
}
@@ -8,17 +28,35 @@ EqualizerView::EqualizerView()
void EqualizerView::setupScreen()
{
EqualizerViewBase::setupScreen();
toggleButton1.forceState(AudioEffects_GetParams()->equalizer.enabled);
bandSlider1.setValue((int16_t)((AudioEffects_GetParams()->equalizer.bands[0].gain_db + 24.0f) / 48.0f * 100.0f));
bandSlider2.setValue((int16_t)((AudioEffects_GetParams()->equalizer.bands[1].gain_db + 24.0f) / 48.0f * 100.0f));
bandSlider3.setValue((int16_t)((AudioEffects_GetParams()->equalizer.bands[2].gain_db + 24.0f) / 48.0f * 100.0f));
bandSlider4.setValue((int16_t)((AudioEffects_GetParams()->equalizer.bands[3].gain_db + 24.0f) / 48.0f * 100.0f));
bandSlider5.setValue((int16_t)((AudioEffects_GetParams()->equalizer.bands[4].gain_db + 24.0f) / 48.0f * 100.0f));
bandSlider6.setValue((int16_t)((AudioEffects_GetParams()->equalizer.bands[5].gain_db + 24.0f) / 48.0f * 100.0f));
bandSlider7.setValue((int16_t)((AudioEffects_GetParams()->equalizer.bands[6].gain_db + 24.0f) / 48.0f * 100.0f));
bandSlider8.setValue((int16_t)((AudioEffects_GetParams()->equalizer.bands[7].gain_db + 24.0f) / 48.0f * 100.0f));
bandSlider9.setValue((int16_t)((AudioEffects_GetParams()->equalizer.bands[8].gain_db + 24.0f) / 48.0f * 100.0f));
bandSlider10.setValue((int16_t)((AudioEffects_GetParams()->equalizer.bands[9].gain_db + 24.0f) / 48.0f * 100.0f));
const touchgfx::colortype accent = ui::accent(ui::EFFECT_EQUALIZER);
insert(&box1, header);
ui::layoutEffectHeader(header, accent, buttonWithLabel1, textArea1, toggleButton1);
zeroDbLine.setPosition(12, ZERO_DB_Y, ui::SCREEN_W - 24, 1);
zeroDbLine.setColor(ui::textMuted());
zeroDbLine.setAlpha(120);
insert(&header, zeroDbLine);
touchgfx::Slider* sliders[10] = { &bandSlider1, &bandSlider2, &bandSlider3, &bandSlider4, &bandSlider5,
&bandSlider6, &bandSlider7, &bandSlider8, &bandSlider9, &bandSlider10 };
touchgfx::TextArea* labels[10] = { &textArea2, &textArea2_1, &textArea2_2, &textArea2_3, &textArea2_4,
&textArea2_5, &textArea2_6, &textArea2_7, &textArea2_8, &textArea2_9 };
const FxEqualizerParams& p = AudioEffects_GetParams()->equalizer;
toggleButton1.forceState(p.enabled);
for (int i = 0; i < 10; i++)
{
const int16_t x = BAND_X0 + i * BAND_STEP;
sliders[i]->setXY(x, SLIDER_Y);
labels[i]->setPosition(x - 10, LABEL_Y, 76, 24);
labels[i]->setColor(ui::textMuted());
values[i].init(touchgfx::TypedText(T_VALUE_S_CENTER), accent, x - 10, VALUE_Y, 76, 24);
add(values[i]);
sliders[i]->setValue((int16_t)((p.bands[i].gain_db + GAIN_RANGE_DB / 2.0f) / GAIN_RANGE_DB * 100.0f + 0.5f));
values[i].showDb(sliderToDb(sliders[i]->getValue()));
}
}
void EqualizerView::tearDownScreen()
@@ -31,43 +69,19 @@ void EqualizerView::toggleClicked()
AudioEffects_GetParams()->equalizer.enabled = toggleButton1.getState();
}
void EqualizerView::sliderBand1Changed(int value)
void EqualizerView::setBand(int index, int value)
{
AudioEffects_GetParams()->equalizer.bands[0].gain_db = (value / 100.0f) * 48.0f - 24.0f;
}
void EqualizerView::sliderBand2Changed(int value)
{
AudioEffects_GetParams()->equalizer.bands[1].gain_db = (value / 100.0f) * 48.0f - 24.0f;
}
void EqualizerView::sliderBand3Changed(int value)
{
AudioEffects_GetParams()->equalizer.bands[2].gain_db = (value / 100.0f) * 48.0f - 24.0f;
}
void EqualizerView::sliderBand4Changed(int value)
{
AudioEffects_GetParams()->equalizer.bands[3].gain_db = (value / 100.0f) * 48.0f - 24.0f;
}
void EqualizerView::sliderBand5Changed(int value)
{
AudioEffects_GetParams()->equalizer.bands[4].gain_db = (value / 100.0f) * 48.0f - 24.0f;
}
void EqualizerView::sliderBand6Changed(int value)
{
AudioEffects_GetParams()->equalizer.bands[5].gain_db = (value / 100.0f) * 48.0f - 24.0f;
}
void EqualizerView::sliderBand7Changed(int value)
{
AudioEffects_GetParams()->equalizer.bands[6].gain_db = (value / 100.0f) * 48.0f - 24.0f;
}
void EqualizerView::sliderBand8Changed(int value)
{
AudioEffects_GetParams()->equalizer.bands[7].gain_db = (value / 100.0f) * 48.0f - 24.0f;
}
void EqualizerView::sliderBand9Changed(int value)
{
AudioEffects_GetParams()->equalizer.bands[8].gain_db = (value / 100.0f) * 48.0f - 24.0f;
}
void EqualizerView::sliderBand10Changed(int value)
{
AudioEffects_GetParams()->equalizer.bands[9].gain_db = (value / 100.0f) * 48.0f - 24.0f;
AudioEffects_GetParams()->equalizer.bands[index].gain_db = (value / 100.0f) * GAIN_RANGE_DB - GAIN_RANGE_DB / 2.0f;
values[index].showDb(sliderToDb(value));
}
void EqualizerView::sliderBand1Changed(int value) { setBand(0, value); }
void EqualizerView::sliderBand2Changed(int value) { setBand(1, value); }
void EqualizerView::sliderBand3Changed(int value) { setBand(2, value); }
void EqualizerView::sliderBand4Changed(int value) { setBand(3, value); }
void EqualizerView::sliderBand5Changed(int value) { setBand(4, value); }
void EqualizerView::sliderBand6Changed(int value) { setBand(5, value); }
void EqualizerView::sliderBand7Changed(int value) { setBand(6, value); }
void EqualizerView::sliderBand8Changed(int value) { setBand(7, value); }
void EqualizerView::sliderBand9Changed(int value) { setBand(8, value); }
void EqualizerView::sliderBand10Changed(int value) { setBand(9, value); }
@@ -1,16 +1,28 @@
#include <gui/initscreen_screen/InitScreenView.hpp>
InitScreenView::InitScreenView()
{
}
void InitScreenView::setupScreen()
{
InitScreenViewBase::setupScreen();
}
void InitScreenView::tearDownScreen()
{
InitScreenViewBase::tearDownScreen();
}
#include <gui/initscreen_screen/InitScreenView.hpp>
#include <gui/common/UiTheme.hpp>
InitScreenView::InitScreenView()
{
}
void InitScreenView::setupScreen()
{
InitScreenViewBase::setupScreen();
/* Titre au-dessus du bouton central, invite en dessous */
title.setPosition(0, 26, ui::SCREEN_W, 48);
title.setTypedText(touchgfx::TypedText(T_APP_TITLE));
title.setColor(ui::textPrimary());
add(title);
hint.setPosition(0, 424, ui::SCREEN_W, 28);
hint.setTypedText(touchgfx::TypedText(T_TAP_TO_START));
hint.setColor(ui::textMuted());
add(hint);
}
void InitScreenView::tearDownScreen()
{
InitScreenViewBase::tearDownScreen();
}
@@ -1,6 +1,14 @@
#include <gui/octaver_screen/OctaverView.hpp>
#include <audio_effects.h>
namespace
{
/* 5 colonnes : libelle d'octave + niveau a gauche, curseur vertical (56x352) a droite */
const int16_t COLUMN_X0 = 30;
const int16_t COLUMN_STEP = 152;
const int16_t SLIDER_Y = ui::HEADER_H + 20;
}
OctaverView::OctaverView()
{
}
@@ -8,12 +16,34 @@ OctaverView::OctaverView()
void OctaverView::setupScreen()
{
OctaverViewBase::setupScreen();
toggleButton1.forceState(AudioEffects_GetParams()->octaver.enabled);
slider1.setValue((int16_t)(AudioEffects_GetParams()->octaver.level_down2 * 100.0f));
slider2.setValue((int16_t)(AudioEffects_GetParams()->octaver.level_down1 * 100.0f));
slider3.setValue((int16_t)(AudioEffects_GetParams()->octaver.level_dry * 100.0f));
slider4.setValue((int16_t)(AudioEffects_GetParams()->octaver.level_up1 * 100.0f));
slider5.setValue((int16_t)(AudioEffects_GetParams()->octaver.level_up2 * 100.0f));
const touchgfx::colortype accent = ui::accent(ui::EFFECT_OCTAVER);
insert(&box1, header);
ui::layoutEffectHeader(header, accent, buttonWithLabel1, textArea1, toggleButton1);
touchgfx::TextArea* labels[5] = { &textArea2, &textArea3, &textArea4, &textArea5, &textArea6 };
touchgfx::Slider* sliders[5] = { &slider1, &slider2, &slider3, &slider4, &slider5 };
for (int i = 0; i < 5; i++)
{
const int16_t x0 = COLUMN_X0 + i * COLUMN_STEP;
labels[i]->setPosition(x0, 220, 76, 46);
labels[i]->setColor(ui::textPrimary());
sliders[i]->setXY(x0 + 80, SLIDER_Y);
values[i].init(touchgfx::TypedText(T_VALUE_S_CENTER), accent, x0, 272, 76, 26);
add(values[i]);
}
FxOctaverParams& p = AudioEffects_GetParams()->octaver;
toggleButton1.forceState(p.enabled);
slider1.setValue((int16_t)(p.level_down2 * 100.0f + 0.5f));
slider2.setValue((int16_t)(p.level_down1 * 100.0f + 0.5f));
slider3.setValue((int16_t)(p.level_dry * 100.0f + 0.5f));
slider4.setValue((int16_t)(p.level_up1 * 100.0f + 0.5f));
slider5.setValue((int16_t)(p.level_up2 * 100.0f + 0.5f));
for (int i = 0; i < 5; i++)
{
showLevel(i, sliders[i]->getValue());
}
}
void OctaverView::tearDownScreen()
@@ -21,6 +51,11 @@ void OctaverView::tearDownScreen()
OctaverViewBase::tearDownScreen();
}
void OctaverView::showLevel(int index, int value)
{
values[index].show("%d %%", value);
}
void OctaverView::toggleClicked()
{
AudioEffects_GetParams()->octaver.enabled = toggleButton1.getState();
@@ -29,20 +64,25 @@ void OctaverView::toggleClicked()
void OctaverView::slider1Clicked(int value)
{
AudioEffects_GetParams()->octaver.level_down2 = value / 100.0f;
showLevel(0, value);
}
void OctaverView::slider2Clicked(int value)
{
AudioEffects_GetParams()->octaver.level_down1 = value / 100.0f;
showLevel(1, value);
}
void OctaverView::slider3Clicked(int value)
{
AudioEffects_GetParams()->octaver.level_dry = value / 100.0f;
showLevel(2, value);
}
void OctaverView::slider4Clicked(int value)
{
AudioEffects_GetParams()->octaver.level_up1 = value / 100.0f;
showLevel(3, value);
}
void OctaverView::slider5Clicked(int value)
{
AudioEffects_GetParams()->octaver.level_up2 = value / 100.0f;
showLevel(4, value);
}
@@ -9,6 +9,11 @@ OscilloView::OscilloView()
void OscilloView::setupScreen()
{
OscilloViewBase::setupScreen();
insert(&box1, header);
ui::layoutEffectHeader(header, ui::accent(ui::EFFECT_SPECTRUM), buttonWithLabel1, textArea1, toggleButton1);
textArea1.setTypedText(touchgfx::TypedText(T_SPECTRUM));
image2.setXY(530, ui::HEADER_H + 10);
textArea2.setXY(577, ui::HEADER_H + 40);
toggleButton1.forceState(AudioAnalysis_IsEnabled());
/* Echelle du graphe en dB (affichage uniquement, pas une mesure calibree) :
@@ -8,10 +8,26 @@ OverdriveView::OverdriveView()
void OverdriveView::setupScreen()
{
OverdriveViewBase::setupScreen();
toggleButton1.forceState(AudioEffects_GetParams()->overdrive.enabled);
slider1.setValue((int16_t)(AudioEffects_GetParams()->overdrive.drive * 100.0f));
slider2.setValue((int16_t)(AudioEffects_GetParams()->overdrive.tone * 100.0f));
slider3.setValue((int16_t)(AudioEffects_GetParams()->overdrive.level * 100.0f));
const touchgfx::colortype accent = ui::accent(ui::EFFECT_OVERDRIVE);
insert(&box1, header);
ui::layoutEffectHeader(header, accent, buttonWithLabel1, textArea1, toggleButton1);
ui::layoutParamRow(textArea2, slider1, values[0], accent, 120);
ui::layoutParamRow(textArea2_1, slider2, values[1], accent, 230);
ui::layoutParamRow(textArea2_2, slider3, values[2], accent, 340);
for (int i = 0; i < 3; i++)
{
add(values[i]);
}
FxOverdriveParams& p = AudioEffects_GetParams()->overdrive;
toggleButton1.forceState(p.enabled);
slider1.setValue((int16_t)(p.drive * 100.0f + 0.5f));
slider2.setValue((int16_t)(p.tone * 100.0f + 0.5f));
slider3.setValue((int16_t)(p.level * 100.0f + 0.5f));
values[0].show("%d %%", slider1.getValue());
values[1].show("%d %%", slider2.getValue());
values[2].show("%d %%", slider3.getValue());
}
void OverdriveView::tearDownScreen()
@@ -27,12 +43,15 @@ void OverdriveView::toggleClicked()
void OverdriveView::sliderDriveChanged(int value)
{
AudioEffects_GetParams()->overdrive.drive = value / 100.0f;
values[0].show("%d %%", value);
}
void OverdriveView::sliderToneChanged(int value)
{
AudioEffects_GetParams()->overdrive.tone = value / 100.0f;
values[1].show("%d %%", value);
}
void OverdriveView::sliderLevelChanged(int value)
{
AudioEffects_GetParams()->overdrive.level = value / 100.0f;
values[2].show("%d %%", value);
}
@@ -1,17 +1,105 @@
#include <gui/overview_screen/OverviewView.hpp>
#include <gui/common/FrontendApplication.hpp>
#include <audio_effects.h>
#include <audio_looper.h>
#include <touchgfx/canvas_widget_renderer/CanvasWidgetRenderer.hpp>
OverviewView::OverviewView() : repeatButtonWasPressed(false)
namespace
{
/* Grille 3x2 des cartes d'effet */
const int16_t GRID_X = 20;
const int16_t GRID_Y = 96;
const int16_t GRID_GAP = 14;
/* Taux de rafraichissement IHM approximatif, sert uniquement a estimer la duree
* de lecture du looper pour l'affichage. */
const uint32_t UI_TICKS_PER_SECOND = 60;
const uint32_t LOOPER_MAX_TICKS = AUDIO_LOOPER_MAX_SECONDS * UI_TICKS_PER_SECOND;
const int16_t REC_BUTTON_X = 14;
const int16_t REC_BUTTON_Y = 366; /* bouton 128x116, ombre comprise */
}
OverviewView::OverviewView()
: cardOpenCallback(this, &OverviewView::onCardOpen),
repeatButtonWasPressed(false),
looperState(LOOPER_IDLE),
looperTicks(0),
playTicksLeft(0)
{
touchgfx::CanvasWidgetRenderer::setupBuffer(canvasBuffer, CANVAS_BUFFER_SIZE);
}
OverviewView::~OverviewView()
{
touchgfx::CanvasWidgetRenderer::resetBuffer();
}
void OverviewView::setupScreen()
{
OverviewViewBase::setupScreen();
toggleButton1.forceState(AudioEffects_GetParams()->audio_on_off);
slider1.setValue((int16_t)(AudioEffects_GetParams()->master_volume * 100.0f));
AudioEffectsParams* params = AudioEffects_GetParams();
/* --- Bandeau du haut : marche/arret + volume --- */
header.setAccent(ui::surfaceBorder());
insert(&box1, header);
toggleButton1.setXY(16, 10);
scalableImage1.setPosition(204, 18, 44, 44);
scalableImage1.setAlpha(200);
slider1.setXY(252, 14);
volumeValue.init(touchgfx::TypedText(T_VALUE_M_LEFT), ui::textPrimary(), 712, 24, 84, 34);
add(volumeValue);
/* --- Grille des effets (remplace les boutons texte generes) --- */
buttonWithLabel1.setVisible(false);
buttonWithLabel2.setVisible(false);
buttonWithLabel3.setVisible(false);
buttonWithLabel4.setVisible(false);
buttonWithLabel5.setVisible(false);
buttonWithLabel6.setVisible(false);
cards[0].setup(ui::EFFECT_OCTAVER, T_CARD_OCTAVER, T_DESC_OCTAVER, &params->octaver.enabled, cardOpenCallback);
cards[1].setup(ui::EFFECT_EQUALIZER, T_CARD_EQUALIZER, T_DESC_EQUALIZER, &params->equalizer.enabled, cardOpenCallback);
cards[2].setup(ui::EFFECT_OVERDRIVE, T_CARD_OVERDRIVE, T_DESC_OVERDRIVE, &params->overdrive.enabled, cardOpenCallback);
cards[3].setup(ui::EFFECT_SATURATION, T_CARD_SATURATION, T_DESC_SATURATION, &params->saturation.enabled, cardOpenCallback);
cards[4].setup(ui::EFFECT_ECHO, T_CARD_ECHO, T_DESC_ECHO, &params->echo.enabled, cardOpenCallback);
cards[5].setup(ui::EFFECT_REVERB, T_CARD_REVERB, T_DESC_REVERB, &params->reverb.enabled, cardOpenCallback);
for (int i = 0; i < 6; i++)
{
const int16_t col = i % 3;
const int16_t row = i / 3;
cards[i].setXY(GRID_X + col * (EffectCard::WIDTH + GRID_GAP),
GRID_Y + row * (EffectCard::HEIGHT + GRID_GAP));
add(cards[i]);
}
/* --- Bas d'ecran : looper (maintenir) + spectre --- */
repeatButton1.setXY(REC_BUTTON_X, REC_BUTTON_Y);
recDot.setPosition(REC_BUTTON_X + 64 - 18, REC_BUTTON_Y + 52 - 18, 36, 36);
recDot.setCenter(18, 18);
recDot.setRadius(14);
recDot.setLineWidth(0);
recDot.setPainter(recDotPainter);
add(recDot);
looperTitle.setPosition(146, 392, 210, 34);
looperTitle.setTypedText(touchgfx::TypedText(T_LOOPER));
looperTitle.setColor(ui::textPrimary());
add(looperTitle);
looperStatus.setPosition(146, 428, 220, 26);
add(looperStatus);
buttonWithLabel7.setXY(366, 380);
buttonWithLabel7.setLabelText(touchgfx::TypedText(T_SPECTRUM));
/* --- Etat initial --- */
toggleButton1.forceState(params->audio_on_off);
const int volume = (int)(params->master_volume * 100.0f + 0.5f);
slider1.setValue((int16_t)volume);
volumeValue.show("%d %%", volume);
setLooperState(LOOPER_IDLE);
}
void OverviewView::tearDownScreen()
@@ -19,6 +107,47 @@ void OverviewView::tearDownScreen()
OverviewViewBase::tearDownScreen();
}
void OverviewView::onCardOpen(const EffectCard& card)
{
FrontendApplication& app = application();
switch (card.getEffect())
{
case ui::EFFECT_OCTAVER: app.gotoOctaverScreenNoTransition(); break;
case ui::EFFECT_EQUALIZER: app.gotoEqualizerScreenNoTransition(); break;
case ui::EFFECT_OVERDRIVE: app.gotoOverdriveScreenNoTransition(); break;
case ui::EFFECT_SATURATION: app.gotoSaturationScreenNoTransition(); break;
case ui::EFFECT_ECHO: app.gotoEchoScreenNoTransition(); break;
case ui::EFFECT_REVERB: app.gotoReverbScreenNoTransition(); break;
default: break;
}
}
void OverviewView::setLooperState(LooperState state)
{
looperState = state;
switch (state)
{
case LOOPER_RECORDING:
looperStatus.setTypedText(touchgfx::TypedText(T_LOOPER_REC));
looperStatus.setColor(ui::rgb(255, 80, 70));
recDotPainter.setColor(ui::rgb(255, 60, 50));
break;
case LOOPER_PLAYING:
looperStatus.setTypedText(touchgfx::TypedText(T_LOOPER_PLAY));
looperStatus.setColor(ui::accent(ui::EFFECT_ECHO));
recDotPainter.setColor(ui::accent(ui::EFFECT_ECHO));
break;
case LOOPER_IDLE:
default:
looperStatus.setTypedText(touchgfx::TypedText(T_LOOPER_HINT));
looperStatus.setColor(ui::textMuted());
recDotPainter.setColor(ui::rgb(150, 40, 34));
break;
}
looperStatus.invalidate();
recDot.invalidate();
}
void OverviewView::handleTickEvent()
{
OverviewViewBase::handleTickEvent();
@@ -31,12 +160,29 @@ void OverviewView::handleTickEvent()
if (pressed && !repeatButtonWasPressed)
{
AudioLooper_StartRecording();
looperTicks = 0;
setLooperState(LOOPER_RECORDING);
}
else if (!pressed && repeatButtonWasPressed)
{
AudioLooper_StopRecordingAndPlay();
uint32_t recorded = looperTicks < LOOPER_MAX_TICKS ? looperTicks : LOOPER_MAX_TICKS;
playTicksLeft = (uint32_t)(recorded / AUDIO_LOOPER_PLAYBACK_RATIO);
setLooperState(playTicksLeft > 0 ? LOOPER_PLAYING : LOOPER_IDLE);
}
repeatButtonWasPressed = pressed;
if (looperState == LOOPER_RECORDING)
{
looperTicks++;
}
else if (looperState == LOOPER_PLAYING)
{
if (playTicksLeft == 0 || --playTicksLeft == 0)
{
setLooperState(LOOPER_IDLE);
}
}
}
void OverviewView::toggleAudioOnOFF()
@@ -47,6 +193,7 @@ void OverviewView::toggleAudioOnOFF()
void OverviewView::slider1Changed(int value)
{
AudioEffects_GetParams()->master_volume = value / 100.0f;
volumeValue.show("%d %%", value);
/* Le volume pilote l'etat marche/arret (0 = off, non nul = on), mais pas
* l'inverse : agir sur le toggle ne doit pas modifier le volume. */
@@ -8,10 +8,30 @@ ReverbView::ReverbView()
void ReverbView::setupScreen()
{
ReverbViewBase::setupScreen();
toggleButton1.forceState(AudioEffects_GetParams()->reverb.enabled);
slider1.setValue((int16_t)(AudioEffects_GetParams()->reverb.room_size * 100.0f));
slider2.setValue((int16_t)(AudioEffects_GetParams()->reverb.damping * 100.0f));
slider3.setValue((int16_t)(AudioEffects_GetParams()->reverb.mix * 100.0f));
/* Libelles generes dans l'ordre inverse des curseurs, et celui de la taille
* de piece affichait "DRIVE" */
textArea2_2.setTypedText(touchgfx::TypedText(T_ROOMSIZE));
const touchgfx::colortype accent = ui::accent(ui::EFFECT_REVERB);
insert(&box1, header);
ui::layoutEffectHeader(header, accent, buttonWithLabel1, textArea1, toggleButton1);
ui::layoutParamRow(textArea2_2, slider1, values[0], accent, 120);
ui::layoutParamRow(textArea2_1, slider2, values[1], accent, 230);
ui::layoutParamRow(textArea2, slider3, values[2], accent, 340);
for (int i = 0; i < 3; i++)
{
add(values[i]);
}
FxReverbParams& p = AudioEffects_GetParams()->reverb;
toggleButton1.forceState(p.enabled);
slider1.setValue((int16_t)(p.room_size * 100.0f + 0.5f));
slider2.setValue((int16_t)(p.damping * 100.0f + 0.5f));
slider3.setValue((int16_t)(p.mix * 100.0f + 0.5f));
values[0].show("%d %%", slider1.getValue());
values[1].show("%d %%", slider2.getValue());
values[2].show("%d %%", slider3.getValue());
}
void ReverbView::tearDownScreen()
@@ -27,12 +47,15 @@ void ReverbView::toggleClicked()
void ReverbView::sliderTailleChanged(int value)
{
AudioEffects_GetParams()->reverb.room_size = value / 100.0f;
values[0].show("%d %%", value);
}
void ReverbView::sliderAmortiChanged(int value)
{
AudioEffects_GetParams()->reverb.damping = value / 100.0f;
values[1].show("%d %%", value);
}
void ReverbView::sliderMixChanged(int value)
{
AudioEffects_GetParams()->reverb.mix = value / 100.0f;
values[2].show("%d %%", value);
}
@@ -8,9 +8,21 @@ SaturationView::SaturationView()
void SaturationView::setupScreen()
{
SaturationViewBase::setupScreen();
toggleButton1.forceState(AudioEffects_GetParams()->saturation.enabled);
slider1.setValue((int16_t)(AudioEffects_GetParams()->saturation.drive * 100.0f));
slider2.setValue((int16_t)(AudioEffects_GetParams()->saturation.level * 100.0f));
const touchgfx::colortype accent = ui::accent(ui::EFFECT_SATURATION);
insert(&box1, header);
ui::layoutEffectHeader(header, accent, buttonWithLabel1, textArea1, toggleButton1);
ui::layoutParamRow(textArea2, slider1, values[0], accent, 150);
ui::layoutParamRow(textArea2_1, slider2, values[1], accent, 280);
add(values[0]);
add(values[1]);
FxSaturationParams& p = AudioEffects_GetParams()->saturation;
toggleButton1.forceState(p.enabled);
slider1.setValue((int16_t)(p.drive * 100.0f + 0.5f));
slider2.setValue((int16_t)(p.level * 100.0f + 0.5f));
values[0].show("%d %%", slider1.getValue());
values[1].show("%d %%", slider2.getValue());
}
void SaturationView::tearDownScreen()
@@ -26,8 +38,10 @@ void SaturationView::toggleClicked()
void SaturationView::sliderDriveClicked(int value)
{
AudioEffects_GetParams()->saturation.drive = value / 100.0f;
values[0].show("%d %%", value);
}
void SaturationView::sliderLevelClicked(int value)
{
AudioEffects_GetParams()->saturation.level = value / 100.0f;
values[1].show("%d %%", value);
}