Files
tactility_apps/Apps/LuaGame/main/Source/audio.cpp
T
Adolfo 827fdb41c2 feat(LuaGame): Lua interpreter game engine with audio, 17 FPS, 4.5x ball speed
- Embed Lua 5.4.7 source to avoid missing symbols (clearerr, clock, getenv, etc)
- Provide local stubs for missing libc and avoid unexported LVGL cache APIs
- Fix float handling in sys.* bindings (checknumber vs checkinteger)
- Move Lua init and game loop to dedicated 16K FreeRTOS task to avoid GUI 4K stack overflow
- Implement sys API: clear, print (8x8 bitmap font direct FB), rect, circle, line, touch, sfx, tone
- Audio via SfxEngine (SfxId mapping, playNote for tone)
- Ball speed 2 -> 4.5, FPS counter (~17 FPS after direct FB text optimization)
- Supports loading from /sdcard/lua/breakout.lua and embedded fallback
- Verified symbols: 0 missing, builds esp32s3, installs on 192.168.68.107
2026-07-31 12:52:02 -04:00

79 lines
3.1 KiB
C++

#include "audio.h"
#include "SfxEngine.h"
#include <string.h>
#include <stdio.h>
#include <strings.h>
static SfxEngine* g_engine = nullptr;
void audio_init(void) {
if (g_engine) return;
g_engine = new SfxEngine();
if (!g_engine->start()) {
printf("[Audio] SfxEngine start failed\n");
delete g_engine;
g_engine = nullptr;
} else {
printf("[Audio] SfxEngine started\n");
}
}
void audio_deinit(void) {
if (g_engine) {
g_engine->stop();
delete g_engine;
g_engine = nullptr;
printf("[Audio] SfxEngine stopped\n");
}
}
static SfxId sfx_name_to_id(const char* name) {
if (!name) return SfxId::Click;
if (strcasecmp(name, "confirm")==0) return SfxId::Confirm;
if (strcasecmp(name, "coin")==0) return SfxId::Coin;
if (strcasecmp(name, "hurt")==0) return SfxId::Hurt;
if (strcasecmp(name, "gameover")==0) return SfxId::GameOver;
if (strcasecmp(name, "levelup")==0) return SfxId::LevelUp;
if (strcasecmp(name, "powerup")==0) return SfxId::Powerup;
if (strcasecmp(name, "brickhit")==0) return SfxId::BrickHit;
if (strcasecmp(name, "click")==0) return SfxId::Click;
if (strcasecmp(name, "blip")==0) return SfxId::Blip;
if (strcasecmp(name, "jump")==0) return SfxId::Jump;
if (strcasecmp(name, "laser")==0) return SfxId::Laser;
if (strcasecmp(name, "explosion")==0) return SfxId::Explosion;
if (strcasecmp(name, "pickup")==0) return SfxId::Pickup;
if (strcasecmp(name, "alert")==0) return SfxId::Alert;
if (strcasecmp(name, "success")==0) return SfxId::Success;
// default mapping
return SfxId::Click;
}
void audio_play_sfx(const char* name) {
if (!g_engine) return;
SfxId id = sfx_name_to_id(name);
g_engine->play(id);
printf("[Audio] sfx %s -> %d\n", name, (int)id);
}
void audio_play_tone(int note, int duration_ms, const char* waveform, float volume) {
if (!g_engine) return;
if (volume <=0) volume = 0.5f;
if (duration_ms <=0) duration_ms = 80;
// waveform string: sine, square, triangle, etc
SfxWaveType wave = SfxWaveType::Square;
if (waveform) {
if (strcasecmp(waveform,"sine")==0) wave = SfxWaveType::Sine;
else if (strcasecmp(waveform,"triangle")==0) wave = SfxWaveType::Triangle;
else if (strcasecmp(waveform,"square")==0) wave = SfxWaveType::Square;
else if (strcasecmp(waveform,"saw")==0 || strcasecmp(waveform,"sawtooth")==0) wave = SfxWaveType::Sawtooth;
else if (strcasecmp(waveform,"noise")==0) wave = SfxWaveType::Noise;
else if (strcasecmp(waveform,"pulse")==0) wave = SfxWaveType::Pulse25;
}
// Use voice 0 for tone, playNote API: voice, pitch, durationMs, wave, volume...
// SfxEngine has playNote? Check header: playNote exists.
// The signature in SfxEngine: bool playNote(uint8_t voice, uint8_t pitch, ...)
// We'll use simplified: play note on voice 0
g_engine->playNote(0, (uint8_t)note, (uint16_t)duration_ms, wave, volume);
printf("[Audio] tone note=%d dur=%d wave=%s vol=%.2f\n", note, duration_ms, waveform?waveform:"-", volume);
}