void part3_ex4_mic_visualizer(void)
{
lv_obj_t *scr = lv_screen_active();
lv_obj_set_style_bg_color(scr, lv_color_hex(0x0a0a1e), 0);
/* ===== Title ===== */
lv_obj_t *title = lv_label_create(scr);
lv_label_set_text(title, "Part 3 Ex4: Mic Visualizer");
lv_obj_set_style_text_color(title, lv_color_hex(0x00ff88), 0);
lv_obj_align(title, LV_ALIGN_TOP_MID, 0, 5);
/* ===== Waveform Chart ===== */
mic_chart = lv_chart_create(scr);
lv_obj_set_size(mic_chart, 340, 140);
lv_obj_align(mic_chart, LV_ALIGN_TOP_LEFT, 10, 28);
lv_chart_set_type(mic_chart, LV_CHART_TYPE_LINE);
lv_chart_set_point_count(mic_chart, DISPLAY_POINTS);
lv_chart_set_range(mic_chart, LV_CHART_AXIS_PRIMARY_Y, 0, 100);
lv_chart_set_div_line_count(mic_chart, 4, 5);
lv_obj_set_style_bg_color(mic_chart, lv_color_hex(0x001a00), 0);
lv_obj_set_style_line_color(mic_chart, lv_color_hex(0x003300),
LV_PART_MAIN);
lv_obj_set_style_border_color(mic_chart, lv_color_hex(0x006600), 0);
lv_obj_set_style_border_width(mic_chart, 1, 0);
lv_obj_set_style_size(mic_chart, 0, 0, LV_PART_INDICATOR);
mic_series = lv_chart_add_series(mic_chart,
lv_color_hex(0x00ff00), LV_CHART_AXIS_PRIMARY_Y);
/* ===== VU Meter Bar (แนวตั้ง) ===== */
vu_bar = lv_bar_create(scr);
lv_obj_set_size(vu_bar, 35, 140);
lv_bar_set_range(vu_bar, 0, 100);
lv_bar_set_value(vu_bar, 0, LV_ANIM_OFF);
lv_obj_align(vu_bar, LV_ALIGN_TOP_RIGHT, -15, 28);
/* VU Bar styling */
lv_obj_set_style_bg_color(vu_bar, lv_color_hex(0x1a1a2e), LV_PART_MAIN);
lv_obj_set_style_bg_color(vu_bar, lv_color_hex(0x00cc44),
LV_PART_INDICATOR);
lv_obj_set_style_border_color(vu_bar, lv_color_hex(0x444466), 0);
lv_obj_set_style_border_width(vu_bar, 1, 0);
lv_obj_set_style_radius(vu_bar, 4, 0);
/* VU zone labels */
lv_obj_t *vu_red = lv_label_create(scr);
lv_label_set_text(vu_red, "R");
lv_obj_set_style_text_color(vu_red, lv_color_hex(0xff4444), 0);
lv_obj_align_to(vu_red, vu_bar, LV_ALIGN_OUT_RIGHT_TOP, 5, 10);
lv_obj_t *vu_yel = lv_label_create(scr);
lv_label_set_text(vu_yel, "Y");
lv_obj_set_style_text_color(vu_yel, lv_color_hex(0xffcc00), 0);
lv_obj_align_to(vu_yel, vu_bar, LV_ALIGN_OUT_RIGHT_MID, 5, -15);
lv_obj_t *vu_grn = lv_label_create(scr);
lv_label_set_text(vu_grn, "G");
lv_obj_set_style_text_color(vu_grn, lv_color_hex(0x00cc44), 0);
lv_obj_align_to(vu_grn, vu_bar, LV_ALIGN_OUT_RIGHT_BOTTOM, 5, -10);
/* ===== Info Panel ===== */
level_label = lv_label_create(scr);
lv_label_set_text(level_label, "Level: 0%");
lv_obj_set_style_text_color(level_label, lv_color_hex(0x00ff00), 0);
lv_obj_align(level_label, LV_ALIGN_BOTTOM_LEFT, 10, -45);
peak_label = lv_label_create(scr);
lv_label_set_text(peak_label, "Peak: 0%");
lv_obj_set_style_text_color(peak_label, lv_color_hex(0xffcc00), 0);
lv_obj_align(peak_label, LV_ALIGN_BOTTOM_MID, 0, -45);
rms_label = lv_label_create(scr);
lv_label_set_text(rms_label, "RMS: 0");
lv_obj_set_style_text_color(rms_label, lv_color_hex(0x888888), 0);
lv_obj_align(rms_label, LV_ALIGN_BOTTOM_RIGHT, -10, -45);
/* ===== Volume Control ===== */
lv_obj_t *vol_lbl = lv_label_create(scr);
lv_label_set_text(vol_lbl, "Volume:");
lv_obj_set_style_text_color(vol_lbl, lv_color_hex(0xaaaaaa), 0);
lv_obj_align(vol_lbl, LV_ALIGN_BOTTOM_LEFT, 10, -15);
lv_obj_t *vol_slider = lv_slider_create(scr);
lv_slider_set_range(vol_slider, 1000, 32000);
lv_slider_set_value(vol_slider, sim_volume, LV_ANIM_OFF);
lv_obj_set_width(vol_slider, 180);
lv_obj_align(vol_slider, LV_ALIGN_BOTTOM_LEFT, 80, -15);
lv_obj_add_event_cb(vol_slider, volume_slider_cb,
LV_EVENT_VALUE_CHANGED, NULL);
/* ===== Clipping Warning ===== */
clip_warning = lv_label_create(scr);
lv_label_set_text(clip_warning, "! CLIP !");
lv_obj_set_style_text_color(clip_warning, lv_color_hex(0xff0000), 0);
lv_obj_set_style_text_font(clip_warning, &lv_font_montserrat_16, 0);
lv_obj_align(clip_warning, LV_ALIGN_BOTTOM_RIGHT, -10, -15);
lv_obj_add_flag(clip_warning, LV_OBJ_FLAG_HIDDEN);
/* ===== Timer (50ms for smooth display) ===== */
mic_timer = lv_timer_create(mic_timer_cb, 50, NULL);
}
/* Volume slider callback */
static void volume_slider_cb(lv_event_t *e)
{
if (lv_event_get_code(e) != LV_EVENT_VALUE_CHANGED) return;
lv_obj_t *slider = lv_event_get_target(e);
sim_volume = (int16_t)lv_slider_get_value(slider);
}