ajout oscillo

This commit is contained in:
thomas committed 2026-09-05 21:52:15 +02:00
1 parent 5cf2212fc0
commit f01d3213c0
18 files changed
+740 -11

No files matched your search

+1
View File
@@ -1,6 +1,7 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Boot",
"type": "cortex-debug",
+50
View File
@@ -0,0 +1,50 @@
#ifndef AUDIO_ANALYSIS_H
#define AUDIO_ANALYSIS_H
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* FFT calculee sur 2048 points : le spectre d'un signal reel est symetrique, donc
* seule la moitie (0 a Fe/2) est utile -> exactement 1024 points affichables,
* correspondant a la capacite du widget Graph cote IHM. */
#define AUDIO_ANALYSIS_SAMPLE_RATE_HZ 48000U
#define AUDIO_ANALYSIS_FFT_SIZE 2048U
#define AUDIO_ANALYSIS_NUM_BINS (AUDIO_ANALYSIS_FFT_SIZE / 2U) /* 1024 : 0 a Fe/2 */
/* A appeler une fois au demarrage, comme AudioEffects_Init(). */
void AudioAnalysis_Init(void);
/* A appeler depuis le chemin audio temps reel (ex: push_to_fifo), un echantillon
* a la fois. Ne fait rien (cout quasi nul) tant que l'analyse n'est pas activee. */
void AudioAnalysis_PushSample(float sample);
/* A appeler depuis la tache IHM (jamais depuis le contexte audio) : si un bloc de
* AUDIO_ANALYSIS_FFT_SIZE echantillons est pret, calcule son spectre (fenetrage +
* FFT + magnitude en dB). Retourne true si un nouveau spectre vient d'etre calcule. */
bool AudioAnalysis_Update(void);
/* Spectre courant, AUDIO_ANALYSIS_NUM_BINS valeurs en dB (echelle approximative,
* pour affichage uniquement), du bin 0 (continu) au bin NUM_BINS-1 (~Fe/2). Le
* pas entre deux bins vaut AUDIO_ANALYSIS_SAMPLE_RATE_HZ / AUDIO_ANALYSIS_FFT_SIZE
* (23.4375 Hz ici). Valide apres un AudioAnalysis_Update() ayant retourne true ;
* inchange sinon (dernier spectre calcule). */
const float *AudioAnalysis_GetMagnitudesDb(void);
/* Frequence (en Hz) du bin de plus forte magnitude dans le dernier spectre calcule
* (frequence dominante / pic). Valide dans les memes conditions que
* AudioAnalysis_GetMagnitudesDb(). */
float AudioAnalysis_GetPeakFrequencyHz(void);
/* Active/desactive la capture et le calcul (pilote par le toggle de l'ecran Oscillo). */
void AudioAnalysis_SetEnabled(bool enabled);
bool AudioAnalysis_IsEnabled(void);
#ifdef __cplusplus
}
#endif
#endif /* AUDIO_ANALYSIS_H */
+1
View File
@@ -19,6 +19,7 @@ extern "C" {
typedef struct
{
bool audio_on_off;
float master_volume; /* volume general en sortie de chaine, 0.0 a 1.0 */
FxOctaverParams octaver;
FxEqualizerParams equalizer;
FxOverdriveParams overdrive;
+211
View File
@@ -0,0 +1,211 @@
#include "audio_analysis.h"
#include <math.h>
#include <string.h>
#define FFT_SIZE AUDIO_ANALYSIS_FFT_SIZE
#define NUM_BINS AUDIO_ANALYSIS_NUM_BINS
/* --- Capture en double buffer (ping-pong), ecrite depuis le chemin audio temps
* reel, lue depuis la tache IHM. Un seul ecrivain, un seul lecteur : pas de verrou
* necessaire, meme principe que la FIFO audio principale. --- */
static float g_capture_buf[2][FFT_SIZE];
static uint32_t g_capture_fill_idx = 0;
static uint8_t g_capture_write_buf = 0;
static volatile uint8_t g_capture_ready_buf = 0xFFU; /* 0xFF = aucun buffer complet en attente */
static bool g_analysis_enabled = false;
/* --- Tables precalculees (a l'init uniquement, jamais recalculees en boucle) --- */
static float g_hann_window[FFT_SIZE];
static float g_twiddle_cos[FFT_SIZE / 2U];
static float g_twiddle_sin[FFT_SIZE / 2U];
/* --- Buffers de travail pour la FFT (reels/imaginaires en place) et resultat --- */
static float g_fft_real[FFT_SIZE];
static float g_fft_imag[FFT_SIZE];
static float g_magnitudes_db[NUM_BINS]; /* seule la moitie 0..Fe/2 est conservee */
static float g_peak_freq_hz = 0.0f;
static void AudioAnalysis_BuildTables(void)
{
for (uint32_t i = 0; i < FFT_SIZE; i++)
{
/* Fenetre de Hann : reduit les fuites spectrales dues a la troncature du bloc. */
g_hann_window[i] = 0.5f - 0.5f * cosf(2.0f * (float)M_PI * (float)i / (float)(FFT_SIZE - 1U));
}
for (uint32_t i = 0; i < FFT_SIZE / 2U; i++)
{
float angle = -2.0f * (float)M_PI * (float)i / (float)FFT_SIZE;
g_twiddle_cos[i] = cosf(angle);
g_twiddle_sin[i] = sinf(angle);
}
}
/* Permutation en bit-reverse, etape preliminaire classique d'une FFT radix-2
* "decimation in time" calculee en place. */
static void AudioAnalysis_BitReverse(float *real, float *imag)
{
uint32_t j = 0;
for (uint32_t i = 0; i < FFT_SIZE - 1U; i++)
{
if (i < j)
{
float tmp = real[i]; real[i] = real[j]; real[j] = tmp;
tmp = imag[i]; imag[i] = imag[j]; imag[j] = tmp;
}
uint32_t k = FFT_SIZE >> 1U;
while (k <= j)
{
j -= k;
k >>= 1U;
}
j += k;
}
}
/* FFT radix-2 iterative (Cooley-Tukey), en place, a partir des tables de twiddle
* precalculees. Complexite O(N log N), largement dans les capacites d'un Cortex-M7
* a FPU materielle pour N=1024, execute hors du chemin audio temps reel. */
static void AudioAnalysis_ComputeFFT(float *real, float *imag)
{
AudioAnalysis_BitReverse(real, imag);
for (uint32_t size = 2U; size <= FFT_SIZE; size <<= 1U)
{
uint32_t half = size >> 1U;
uint32_t table_step = FFT_SIZE / size;
for (uint32_t i = 0; i < FFT_SIZE; i += size)
{
for (uint32_t k = 0; k < half; k++)
{
uint32_t twiddle_idx = k * table_step;
float c = g_twiddle_cos[twiddle_idx];
float s = g_twiddle_sin[twiddle_idx];
uint32_t idx1 = i + k;
uint32_t idx2 = i + k + half;
float tr = real[idx2] * c - imag[idx2] * s;
float ti = real[idx2] * s + imag[idx2] * c;
real[idx2] = real[idx1] - tr;
imag[idx2] = imag[idx1] - ti;
real[idx1] += tr;
imag[idx1] += ti;
}
}
}
}
void AudioAnalysis_Init(void)
{
memset(g_capture_buf, 0, sizeof(g_capture_buf));
g_capture_fill_idx = 0;
g_capture_write_buf = 0;
g_capture_ready_buf = 0xFFU;
g_analysis_enabled = false;
memset(g_magnitudes_db, 0, sizeof(g_magnitudes_db));
AudioAnalysis_BuildTables();
}
void AudioAnalysis_PushSample(float sample)
{
if (!g_analysis_enabled)
{
return;
}
g_capture_buf[g_capture_write_buf][g_capture_fill_idx] = sample;
g_capture_fill_idx++;
if (g_capture_fill_idx >= FFT_SIZE)
{
g_capture_fill_idx = 0;
g_capture_ready_buf = g_capture_write_buf;
g_capture_write_buf = 1U - g_capture_write_buf;
}
}
bool AudioAnalysis_Update(void)
{
if (!g_analysis_enabled)
{
return false;
}
uint8_t ready = g_capture_ready_buf;
if (ready == 0xFFU)
{
return false;
}
g_capture_ready_buf = 0xFFU;
for (uint32_t i = 0; i < FFT_SIZE; i++)
{
g_fft_real[i] = g_capture_buf[ready][i] * g_hann_window[i];
g_fft_imag[i] = 0.0f;
}
AudioAnalysis_ComputeFFT(g_fft_real, g_fft_imag);
/* Magnitude normalisee (une sinusoide plein-echelle donne ~0dB) puis convertie
* en dB, avec un plancher pour eviter log(0). Destine a un affichage visuel,
* pas a une mesure calibree. Seule la moitie 0..Fe/2 du spectre est conservee :
* le spectre d'un signal reel est symetrique, la seconde moitie n'apporte rien. */
/* Recherche du pic en meme temps que le calcul des magnitudes. Le bin 0 (continu,
* 0Hz) est ignore : une composante DC ne doit pas etre rapportee comme "frequence
* dominante". */
uint32_t peak_bin = 1U;
float peak_mag = 0.0f;
for (uint32_t i = 0; i < NUM_BINS; i++)
{
float re = g_fft_real[i];
float im = g_fft_imag[i];
float mag = sqrtf(re * re + im * im) / ((float)FFT_SIZE / 4.0f);
if (i >= 1U && mag > peak_mag)
{
peak_mag = mag;
peak_bin = i;
}
if (mag < 1.0e-6f)
{
mag = 1.0e-6f;
}
g_magnitudes_db[i] = 20.0f * log10f(mag);
}
g_peak_freq_hz = (float)peak_bin * (float)AUDIO_ANALYSIS_SAMPLE_RATE_HZ / (float)FFT_SIZE;
return true;
}
const float *AudioAnalysis_GetMagnitudesDb(void)
{
return g_magnitudes_db;
}
float AudioAnalysis_GetPeakFrequencyHz(void)
{
return g_peak_freq_hz;
}
void AudioAnalysis_SetEnabled(bool enabled)
{
if (enabled && !g_analysis_enabled)
{
/* Redemarre une capture propre a chaque activation. */
g_capture_fill_idx = 0;
g_capture_write_buf = 0;
g_capture_ready_buf = 0xFFU;
}
g_analysis_enabled = enabled;
}
bool AudioAnalysis_IsEnabled(void)
{
return g_analysis_enabled;
}
+2 -1
View File
@@ -12,6 +12,7 @@ static FxReverbState g_reverbState;
void AudioEffects_Init(void)
{
g_params.audio_on_off = false;
g_params.master_volume = 0.0f;
FxOctaver_Init(&g_octaverState, &g_params.octaver);
FxEqualizer_Init(&g_eqState, &g_params.equalizer);
FxOverdrive_Init(&g_overdriveState, &g_params.overdrive);
@@ -37,7 +38,7 @@ float AudioEffects_Process(float input)
return 0.0f;
}
return sample;
return sample * g_params.master_volume;
}
AudioEffectsParams *AudioEffects_GetParams(void)
+3
View File
@@ -26,6 +26,7 @@
/* USER CODE BEGIN Includes */
#include "stm32h7s78_discovery_audio.h"
#include "audio_effects.h"
#include "audio_analysis.h"
#include <string.h>
/* USER CODE END Includes */
@@ -188,6 +189,7 @@ int main(void)
fifo_read_idx = 0;
AudioEffects_Init();
AudioAnalysis_Init();
sDmaConfig.Address = (uint32_t)adf_buf;
sDmaConfig.DataLength = AUDIO_SAMPLES * sizeof(int32_t); /* OCTETS */
@@ -793,6 +795,7 @@ static void push_to_fifo(int32_t raw)
}
float sample = adf_sample_to_float(raw);
sample = AudioEffects_Process(sample);
AudioAnalysis_PushSample(sample);
int16_t s = float_to_pcm16(sample);
uint32_t idx = fifo_write_idx & (FIFO_SIZE - 1);
audio_fifo[idx * 2] = s;
+284 -8
View File
@@ -71,7 +71,7 @@
{
"Type": "ButtonWithLabel",
"Name": "buttonWithLabel1",
"Y": 93,
"Y": 134,
"Width": 420,
"Height": 94,
"Pressed": "__generated\\glass_theme_images_widgets_button_regular_height_50_large_rounded_pressed.png",
@@ -93,7 +93,7 @@
{
"Type": "ButtonWithLabel",
"Name": "buttonWithLabel2",
"Y": 281,
"Y": 322,
"Width": 420,
"Height": 94,
"Pressed": "__generated\\glass_theme_images_widgets_button_regular_height_50_large_rounded_pressed.png",
@@ -116,7 +116,7 @@
"Type": "ButtonWithLabel",
"Name": "buttonWithLabel3",
"X": 380,
"Y": 281,
"Y": 322,
"Width": 420,
"Height": 94,
"Pressed": "__generated\\glass_theme_images_widgets_button_regular_height_50_large_rounded_pressed.png",
@@ -138,7 +138,7 @@
{
"Type": "ButtonWithLabel",
"Name": "buttonWithLabel4",
"Y": 187,
"Y": 228,
"Width": 420,
"Height": 94,
"Pressed": "__generated\\glass_theme_images_widgets_button_regular_height_50_large_rounded_pressed.png",
@@ -161,7 +161,7 @@
"Type": "ButtonWithLabel",
"Name": "buttonWithLabel5",
"X": 380,
"Y": 187,
"Y": 228,
"Width": 420,
"Height": 94,
"Pressed": "__generated\\glass_theme_images_widgets_button_regular_height_50_large_rounded_pressed.png",
@@ -184,7 +184,7 @@
"Type": "ButtonWithLabel",
"Name": "buttonWithLabel6",
"X": 380,
"Y": 93,
"Y": 134,
"Width": 420,
"Height": 94,
"Pressed": "__generated\\glass_theme_images_widgets_button_regular_height_50_large_rounded_pressed.png",
@@ -203,16 +203,67 @@
"TextRotation": "0",
"Preset": "glass_theme\\presets\\button\\regular\\height_50\\large_rounded_normal.json"
},
{
"Type": "ButtonWithLabel",
"Name": "buttonWithLabel7",
"X": 190,
"Y": 396,
"Width": 420,
"Height": 94,
"Pressed": "__generated\\glass_theme_images_widgets_button_regular_height_50_large_rounded_pressed.png",
"Released": "__generated\\glass_theme_images_widgets_button_regular_height_50_large_rounded_normal.png",
"TextId": "OSCILLO",
"ReleasedColor": {
"Red": 230,
"Green": 214,
"Blue": 170
},
"PressedColor": {
"Red": 230,
"Green": 214,
"Blue": 170
},
"TextRotation": "0",
"Preset": "glass_theme\\presets\\button\\regular\\height_50\\large_rounded_normal.json"
},
{
"Type": "ToggleButton",
"Name": "toggleButton1",
"X": 118,
"Y": 22,
"X": 135,
"Y": 18,
"Width": 170,
"Height": 60,
"Pressed": "__generated\\glass_theme_images_widgets_togglebutton_large_rounded_text_on_active.png",
"Released": "__generated\\glass_theme_images_widgets_togglebutton_large_rounded_text_off_normal.png",
"Preset": "glass_theme\\presets\\togglebutton\\large\\rounded_active_text.json"
},
{
"Type": "Slider",
"Name": "slider1",
"X": 329,
"Y": 22,
"Width": 456,
"Height": 52,
"IsHorizontalSlider": true,
"BackgroundUnselected": "__generated\\glass_theme_images_widgets_slider_horizontal_thick_track_large.png",
"BackgroundSelected": "__generated\\glass_theme_images_widgets_slider_horizontal_thick_filler_large.png",
"Indicator": "__generated\\glass_theme_images_widgets_slider_horizontal_thick_rounded_dark.png",
"BackgroundX": 28,
"BackgroundY": 21,
"IndicatorMax": 400,
"ValueMax": 100,
"Preset": "glass_theme\\presets\\slider\\horizontal\\thick\\large_rounded_dark.json"
},
{
"Type": "ScalableImage",
"Name": "scalableImage1",
"X": 15,
"Y": 4,
"Width": 105,
"Height": 95,
"Filename": "__generated\\icon_theme_images_hardware_headset_50_50_FFFFFF.svg.png",
"Alpha": 149,
"ScalingAlgorithm": "Bilinear Interpolation"
}
],
"Interactions": [
@@ -298,6 +349,39 @@
"ScreenTransitionType": "ScreenTransitionNone",
"ActionComponent": "Octaver"
}
},
{
"InteractionName": "Interaction8",
"Trigger": {
"Type": "TriggerSliderValueChanged",
"TriggerComponent": "slider1"
},
"Action": {
"Type": "ActionCustom",
"FunctionName": "slider1Changed"
}
},
{
"InteractionName": "Interaction9",
"Trigger": {
"Type": "TriggerSliderValueConfirmed",
"TriggerComponent": "slider1"
},
"Action": {
"Type": "ActionNone"
}
},
{
"InteractionName": "Interaction10",
"Trigger": {
"Type": "TriggerClicked",
"TriggerComponent": "buttonWithLabel7"
},
"Action": {
"Type": "ActionGotoScreen",
"ScreenTransitionType": "ScreenTransitionNone",
"ActionComponent": "Oscillo"
}
}
]
},
@@ -2018,6 +2102,198 @@
}
}
]
},
{
"Name": "Oscillo",
"CanvasBufferSize": 12000,
"Components": [
{
"Type": "Image",
"Name": "image1",
"Y": -1,
"Width": 800,
"Height": 483,
"RelativeFilename": "fondHorlogerie1.png"
},
{
"Type": "Box",
"Name": "box1",
"Width": 800,
"Height": 480,
"Color": {
"Red": 35,
"Green": 24,
"Blue": 15
},
"Alpha": 240
},
{
"Type": "TextArea",
"Name": "textArea1",
"X": 314,
"Y": 26,
"Width": 173,
"Height": 42,
"TextId": "OSCILLO",
"TextRotation": "0",
"Color": {
"Red": 230,
"Green": 214,
"Blue": 170
},
"AutoSize": true
},
{
"Type": "ToggleButton",
"Name": "toggleButton1",
"X": 576,
"Y": 20,
"Width": 170,
"Height": 60,
"Pressed": "__generated\\glass_theme_images_widgets_togglebutton_large_round_text_on_active.png",
"Released": "__generated\\glass_theme_images_widgets_togglebutton_large_round_text_off_normal.png",
"Preset": "glass_theme\\presets\\togglebutton\\large\\round_active_text.json"
},
{
"Type": "ButtonWithLabel",
"Name": "buttonWithLabel1",
"Width": 225,
"Height": 94,
"Pressed": "__generated\\glass_theme_images_widgets_button_regular_height_50_small_rounded_pressed.png",
"Released": "__generated\\glass_theme_images_widgets_button_regular_height_50_small_rounded_normal.png",
"TextId": "BACK",
"ReleasedColor": {
"Red": 230,
"Green": 214,
"Blue": 170
},
"PressedColor": {
"Red": 230,
"Green": 214,
"Blue": 170
},
"TextRotation": "0",
"Preset": "glass_theme\\presets\\button\\regular\\height_50\\small_rounded_normal.json"
},
{
"Type": "StaticGraph",
"Name": "graph1",
"Y": 94,
"Width": 800,
"Height": 386,
"DataSeed": 676876642,
"NumberOfValues": 1024,
"MaxX": 24000.0,
"PrecisionX": "1",
"MaxY": 100.0,
"PrecisionY": "1",
"XAxisScale": 1.0,
"InsertRandomValues": true,
"LabelSizeBottom": 63,
"LabelSizeLeft": 16,
"LabelSizeRight": 16,
"PaddingBottom": 17,
"GraphDrawers": [
{
"Type": "LineDrawer",
"LineWidth": 2,
"FileNameImage": "",
"Color": {
"Red": 20,
"Green": 151,
"Blue": 197
}
}
],
"XAxisGrid": {
"Type": "GraphGrid",
"Color": {
"Red": 230,
"Green": 214,
"Blue": 170
},
"Interval": 2400.0,
"LineWidth": 1
},
"YAxisGrid": {
"Type": "GraphGrid",
"Color": {
"Red": 230,
"Green": 214,
"Blue": 170
},
"Interval": 25.0,
"LineWidth": 1
},
"XAxisLabel": {
"Type": "GraphLabel",
"Interval": 2400.0,
"DecimalSeparator": "Point",
"TextColor": {
"Red": 230,
"Green": 214,
"Blue": 170
},
"TextId": "__SingleUse_2C9Q",
"TextRotation": "270",
"Position": "Bottom"
}
},
{
"Type": "Image",
"Name": "image2",
"X": 535,
"Y": 74,
"Width": 264,
"Height": 80,
"RelativeFilename": "__generated\\glass_theme_images_widgets_button_regular_height_36_medium_round_action.png"
},
{
"Type": "TextArea",
"Name": "textArea2",
"X": 582,
"Y": 104,
"Width": 181,
"Height": 23,
"TextId": "textAreaMax",
"TextRotation": "0",
"Color": {
"Red": 230,
"Green": 214,
"Blue": 170
},
"Wildcard1": {
"TextId": "__SingleUse_U5V0",
"UseBuffer": true,
"BufferSize": 10
}
}
],
"Interactions": [
{
"InteractionName": "Interaction1",
"Trigger": {
"Type": "TriggerClicked",
"TriggerComponent": "buttonWithLabel1"
},
"Action": {
"Type": "ActionGotoScreen",
"ScreenTransitionType": "ScreenTransitionNone",
"ActionComponent": "Overview"
}
},
{
"InteractionName": "Interaction2",
"Trigger": {
"Type": "TriggerClicked",
"TriggerComponent": "toggleButton1"
},
"Action": {
"Type": "ActionCustom",
"FunctionName": "toggleClicked"
}
}
]
}
],
"CustomContainerDefinitions": [],
Binary file not shown.

After

Width:  |  Height:  |  Size: 315 B

+15 -2
View File
@@ -14,6 +14,9 @@
<Text Id="OCTAVER" Alignment="Center" TypographyId="Large">
<Translation Language="GB">OCTAVER</Translation>
</Text>
<Text Id="OSCILLO" Alignment="Center" TypographyId="Large">
<Translation Language="GB">OSCILLO</Translation>
</Text>
<Text Id="OVERDRIVE" Alignment="Center" TypographyId="Large">
<Translation Language="GB" Alignment="Center">OVERDRIVE</Translation>
</Text>
@@ -105,10 +108,20 @@
<Translation Language="GB" Alignment="Center">+2</Translation>
</Text>
</TextGroup>
<TextGroup Id="Unsorted" />
<TextGroup Id="Unsorted">
<Text Id="__SingleUse_U5V0" Alignment="Left" TypographyId="Default">
<Translation Language="GB">100</Translation>
</Text>
<Text Id="textAreaMax" Alignment="Left" TypographyId="Default">
<Translation Language="GB">Max : &lt;d&gt; Hz</Translation>
</Text>
<Text Id="__SingleUse_2C9Q" Alignment="Left" TypographyId="Default">
<Translation Language="GB">&lt;&gt;</Translation>
</Text>
</TextGroup>
</Texts>
<Typographies>
<Typography Id="Default" Font="arial.ttf" Size="20" Bpp="4" IsVector="no" Direction="LTR" FallbackCharacter="?" />
<Typography Id="Default" Font="arial.ttf" Size="20" Bpp="4" IsVector="no" Direction="LTR" FallbackCharacter="?" WidgetWildcardCharacters="-., 0123456789" />
<Typography Id="Large" Font="arial.ttf" Size="40" Bpp="4" IsVector="no" Direction="LTR" FallbackCharacter="?" />
<Typography Id="Small" Font="arial.ttf" Size="10" Bpp="4" IsVector="no" Direction="LTR" FallbackCharacter="?" />
</Typographies>
@@ -0,0 +1,36 @@
#ifndef OSCILLOPRESENTER_HPP
#define OSCILLOPRESENTER_HPP
#include <gui/model/ModelListener.hpp>
#include <mvp/Presenter.hpp>
using namespace touchgfx;
class OscilloView;
class OscilloPresenter : public touchgfx::Presenter, public ModelListener
{
public:
OscilloPresenter(OscilloView& v);
/**
* The activate function is called automatically when this screen is "switched in"
* (ie. made active). Initialization logic can be placed here.
*/
virtual void activate();
/**
* The deactivate function is called automatically when this screen is "switched out"
* (ie. made inactive). Teardown functionality can be placed here.
*/
virtual void deactivate();
virtual ~OscilloPresenter() {}
private:
OscilloPresenter();
OscilloView& view;
};
#endif // OSCILLOPRESENTER_HPP
@@ -0,0 +1,20 @@
#ifndef OSCILLOVIEW_HPP
#define OSCILLOVIEW_HPP
#include <gui_generated/oscillo_screen/OscilloViewBase.hpp>
#include <gui/oscillo_screen/OscilloPresenter.hpp>
class OscilloView : public OscilloViewBase
{
public:
OscilloView();
virtual ~OscilloView() {}
virtual void setupScreen();
virtual void tearDownScreen();
virtual void handleTickEvent();
virtual void toggleClicked();
protected:
};
#endif // OSCILLOVIEW_HPP
@@ -13,6 +13,7 @@ public:
virtual void tearDownScreen();
virtual void toggleAudioOnOFF();
virtual void slider1Changed(int value);
protected:
};
@@ -0,0 +1,18 @@
#include <gui/oscillo_screen/OscilloView.hpp>
#include <gui/oscillo_screen/OscilloPresenter.hpp>
OscilloPresenter::OscilloPresenter(OscilloView& v)
: view(v)
{
}
void OscilloPresenter::activate()
{
}
void OscilloPresenter::deactivate()
{
}
@@ -0,0 +1,59 @@
#include <gui/oscillo_screen/OscilloView.hpp>
#include <audio_analysis.h>
#include <touchgfx/Unicode.hpp>
OscilloView::OscilloView()
{
}
void OscilloView::setupScreen()
{
OscilloViewBase::setupScreen();
toggleButton1.forceState(AudioAnalysis_IsEnabled());
/* Echelle du graphe en dB (affichage uniquement, pas une mesure calibree) :
* de -80dB (proche du plancher de bruit numerique) a +5dB de marge au-dessus
* du 0dB nominal. */
graph1.setGraphRangeY(-80.0f, 5.0f);
/* Axe X en Hz, de 0 a Fe/2 (24kHz) : ce graphe (statique, points X/Y explicites,
* contrairement au precedent DynamicGraph a increment X automatique) recoit
* directement la frequence de chaque bin avec addDataPoint(x, y). */
graph1.setGraphRangeX(0.0f, (float)AUDIO_ANALYSIS_SAMPLE_RATE_HZ / 2.0f);
}
void OscilloView::tearDownScreen()
{
OscilloViewBase::tearDownScreen();
}
void OscilloView::handleTickEvent()
{
OscilloViewBase::handleTickEvent();
if (!AudioAnalysis_IsEnabled())
{
return;
}
if (AudioAnalysis_Update())
{
const float *magnitudesDb = AudioAnalysis_GetMagnitudesDb();
const float binHz = (float)AUDIO_ANALYSIS_SAMPLE_RATE_HZ / (float)AUDIO_ANALYSIS_FFT_SIZE;
graph1.clear();
for (int i = 0; i < (int)AUDIO_ANALYSIS_NUM_BINS; i++)
{
graph1.addDataPoint((float)i * binHz, magnitudesDb[i]);
}
touchgfx::Unicode::snprintf(textArea2Buffer, TEXTAREA2_SIZE, "%d", (int)AudioAnalysis_GetPeakFrequencyHz());
textArea2.setWildcard(textArea2Buffer);
textArea2.invalidate();
}
}
void OscilloView::toggleClicked()
{
AudioAnalysis_SetEnabled(toggleButton1.getState());
}
@@ -10,6 +10,7 @@ void OverviewView::setupScreen()
{
OverviewViewBase::setupScreen();
toggleButton1.forceState(AudioEffects_GetParams()->audio_on_off);
slider1.setValue((int16_t)(AudioEffects_GetParams()->master_volume * 100.0f));
}
void OverviewView::tearDownScreen()
@@ -21,3 +22,15 @@ void OverviewView::toggleAudioOnOFF()
{
AudioEffects_GetParams()->audio_on_off = toggleButton1.getState();
}
void OverviewView::slider1Changed(int value)
{
AudioEffects_GetParams()->master_volume = value / 100.0f;
/* 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. */
bool en = (value != 0);
AudioEffects_GetParams()->audio_on_off = en;
toggleButton1.forceState(en);
toggleButton1.invalidate();
}
+25
View File
@@ -430,6 +430,16 @@
<type>1</type>
<locationURI>PARENT-2-PROJECT_LOC/Appli/TouchGFX/gui/src/octaver_screen/OctaverView.cpp</locationURI>
</link>
<link>
<name>Application/User/gui/OscilloPresenter.cpp</name>
<type>1</type>
<locationURI>PARENT-2-PROJECT_LOC/Appli/TouchGFX/gui/src/oscillo_screen/OscilloPresenter.cpp</locationURI>
</link>
<link>
<name>Application/User/gui/OscilloView.cpp</name>
<type>1</type>
<locationURI>PARENT-2-PROJECT_LOC/Appli/TouchGFX/gui/src/oscillo_screen/OscilloView.cpp</locationURI>
</link>
<link>
<name>Application/User/gui/OverdrivePresenter.cpp</name>
<type>1</type>
@@ -580,6 +590,11 @@
<type>1</type>
<locationURI>PARENT-2-PROJECT_LOC/Appli/TouchGFX/generated/gui_generated/src/octaver_screen/OctaverViewBase.cpp</locationURI>
</link>
<link>
<name>Application/User/generated/OscilloViewBase.cpp</name>
<type>1</type>
<locationURI>PARENT-2-PROJECT_LOC/Appli/TouchGFX/generated/gui_generated/src/oscillo_screen/OscilloViewBase.cpp</locationURI>
</link>
<link>
<name>Application/User/generated/OverdriveViewBase.cpp</name>
<type>1</type>
@@ -620,6 +635,11 @@
<type>1</type>
<locationURI>PARENT-2-PROJECT_LOC/Appli/TouchGFX/generated/images/src/__generated/image_glass_theme_images_widgets_button_icon_round_huge_fill_pressed.cpp</locationURI>
</link>
<link>
<name>Application/User/generated/image_glass_theme_images_widgets_button_regular_height_36_medium_round_action.cpp</name>
<type>1</type>
<locationURI>PARENT-2-PROJECT_LOC/Appli/TouchGFX/generated/images/src/__generated/image_glass_theme_images_widgets_button_regular_height_36_medium_round_action.cpp</locationURI>
</link>
<link>
<name>Application/User/generated/image_glass_theme_images_widgets_button_regular_height_50_large_rounded_normal.cpp</name>
<type>1</type>
@@ -700,6 +720,11 @@
<type>1</type>
<locationURI>PARENT-2-PROJECT_LOC/Appli/TouchGFX/generated/images/src/__generated/image_icon_theme_images_av_fiber_manual_record_50_50_5E3E10.svg.cpp</locationURI>
</link>
<link>
<name>Application/User/generated/image_icon_theme_images_hardware_headset_50_50_FFFFFF.svg.cpp</name>
<type>1</type>
<locationURI>PARENT-2-PROJECT_LOC/Appli/TouchGFX/generated/images/src/__generated/image_icon_theme_images_hardware_headset_50_50_FFFFFF.svg.cpp</locationURI>
</link>
<link>
<name>Application/User/generated/image_fondHorlogerie1.cpp</name>
<type>1</type>
+1
View File
@@ -300,6 +300,7 @@ board_c_files += \
Appli/Core/Src/stm32h7rsxx_hal_timebase_tim.c \
Appli/Core/Src/system_stm32h7rsxx.c \
Appli/Core/Src/audio_effects.c \
Appli/Core/Src/audio_analysis.c \
Appli/Core/Src/fx_octaver.c \
Appli/Core/Src/fx_equalizer.c \
Appli/Core/Src/fx_overdrive.c \