ajout oscillo
This commit is contained in:
1 parent
5cf2212fc0
commit
f01d3213c0
18 files changed
+741
-12
No files matched your search
Vendored
+1
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
|
||||
{
|
||||
"name": "Debug Boot",
|
||||
"type": "cortex-debug",
|
||||
|
||||
@@ -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 */
|
||||
@@ -18,7 +18,8 @@ extern "C" {
|
||||
* octaveur -> egaliseur -> overdrive -> saturation -> echo -> reverberation. */
|
||||
typedef struct
|
||||
{
|
||||
bool audio_on_off;
|
||||
bool audio_on_off;
|
||||
float master_volume; /* volume general en sortie de chaine, 0.0 a 1.0 */
|
||||
FxOctaverParams octaver;
|
||||
FxEqualizerParams equalizer;
|
||||
FxOverdriveParams overdrive;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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": [],
|
||||
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 1.2 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 315 B |
@@ -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 : <d> Hz</Translation>
|
||||
</Text>
|
||||
<Text Id="__SingleUse_2C9Q" Alignment="Left" TypographyId="Default">
|
||||
<Translation Language="GB"><></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();
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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 \
|
||||
|
||||
Reference in new issue
Block a user