Skip to content

Commit

Permalink
LilTracker (#95)
Browse files Browse the repository at this point in the history
keira: add liltracker
keira: allow apps to set their core affinity
keira: replace mutexes with binary semaphores
keira: fix memory corruption due to usage of WiFi methods after deallocation by liltracker
keira: add mutex to servicemanager, start debugging network disabling
sdk: eliminate duplication in Display and Canvas classes by moving shared code into a mixin class (GFX)
sdk: add GFX::drawTextAligned and GFX::getTextBoundsAligned
sdk: reduce serial_log/serial_err string buffer size
sdk: some I2S asshattery.
sdk: fix initial display width/height due to rotation being applied too late
sdk: move buzzer hello tune to Buzzer class
sdk: remove I2S ping sound
sdk: do not memcpy String in Menu::getItem
  • Loading branch information
and3rson committed Apr 13, 2024
1 parent dc848ee commit f4e668a
Show file tree
Hide file tree
Showing 31 changed files with 2,902 additions and 227 deletions.
4 changes: 2 additions & 2 deletions docs/about/index.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
По проєкт
===========
Про проєкт
==========

.. include:: what_is_lilka.rst

Expand Down
3 changes: 3 additions & 0 deletions docs/library/display.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
.. doxygenclass:: lilka::Canvas
:members:

.. doxygenclass:: lilka::GFX
:members:

.. doxygenclass:: lilka::Image
:members:

Expand Down
4 changes: 4 additions & 0 deletions firmware/keira/src/apps/launcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "nes/nesapp.h"
#include "ftp/ftp_server.h"
#include "weather/weather.h"
#include "liltracker/liltracker.h"

#include "icons/demos.h"
#include "icons/sdcard.h"
Expand Down Expand Up @@ -66,6 +67,7 @@ ITEM_LIST app_items = {
ITEM_APP("I2C-сканер", ScanI2CApp),
ITEM_APP("GPIO-мененджер", GPIOManagerApp)},
),
ITEM_APP("ЛілТрекер", LilTrackerApp),
ITEM_APP("Летріс", LetrisApp),
ITEM_APP("Тамагочі", TamagotchiApp),
ITEM_APP("Погода", WeatherApp),
Expand Down Expand Up @@ -267,6 +269,8 @@ void LauncherApp::selectFile(String path) {
AppManager::getInstance()->runApp(new LuaFileRunnerApp(path));
} else if (lowerCasedPath.endsWith(".js")) {
AppManager::getInstance()->runApp(new MJSApp(path));
} else if (lowerCasedPath.endsWith(".lt")) {
AppManager::getInstance()->runApp(new LilTrackerApp(path));
} else {
// Get file size
// lilka::serial_log(path.c_str());
Expand Down
6 changes: 6 additions & 0 deletions firmware/keira/src/apps/liltracker/config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#pragma once

#define CHANNEL_COUNT 3
#define DEFAULT_BPM 400
#define CHANNEL_SIZE 32
#define MAX_VOLUME 128
111 changes: 111 additions & 0 deletions firmware/keira/src/apps/liltracker/effects.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
#include <math.h>
#include <lilka/fmath.h>

#include "effects.h"
#include "note.h"

void effect_none(float time, float relTime, float* frequency, float* amplitude, float* phase, uint8_t param) {
(void)time;
(void)relTime;
(void)frequency;
(void)amplitude;
(void)phase;
(void)param;
}

void effect_arpeggio(float time, float relTime, float* frequency, float* amplitude, float* phase, uint8_t param) {
// This effect arpeggiates the note by changing the frequency of the note at a fixed interval.
// It mimics NES arpeggio that consists of up to 3 notes.

(void)relTime;
(void)amplitude;
(void)param;

constexpr int8_t count = 3; // 3 notes

uint8_t note2offset = (param & 0xF0) >> 4;
uint8_t note3offset = (param & 0x0F);

// duration of each note in milliseconds is 1/60 of a second
float stepDurationMs = 1000.0f / 60.0f;

// Calculate current arpeggio step
int8_t step = ((int64_t)(time / (stepDurationMs / 1000.0f))) % count;

if (step == 0) {
// No change
} else if (step == 1) {
// Use the second note
*frequency = modulate_frequency(*frequency, note2offset);
} else if (step == 2) {
// Use the third note
*frequency = modulate_frequency(*frequency, note3offset);
}
}

void effect_vibrato(float time, float relTime, float* frequency, float* amplitude, float* phase, uint8_t param) {
// This effect modulates the frequency of the note with a sine wave.
// Upper nibble of the parameter is the speed of the vibrato (in Hz)
// Lower nibble of the parameter is the depth of the vibrato (0 to 15, 0 = no vibrato, 15 = one full semitone vibrato)

(void)relTime;
(void)frequency;
(void)amplitude;

uint8_t vibratoFrequency = (param & 0xF0) >> 4;
uint8_t vibratoDepth = param & 0x0F;

// Calculate the depth of vibrato in terms of radians
float phaseModulation = vibratoDepth / 15.0f * lilka::fSin360(time * vibratoFrequency * 360);

// Apply the vibrato phase modulation
*phase += phaseModulation;
}

void effect_tremolo(float time, float relTime, float* frequency, float* amplitude, float* phase, uint8_t param) {
// This effect modulates the amplitude of the note with a sine wave.
// Upper nibble of the parameter is the speed of the tremolo (in Hz)
// Lower nibble of the parameter is the depth of the tremolo (0 to 15, 0 = no tremolo, 15 = max tremolo)

(void)time;
(void)relTime;
(void)frequency;
(void)phase;

uint8_t tremoloFrequency = (param & 0xF0) >> 4;
uint8_t tremoloDepth = (param & 0x0F);

// Calculate the tremolo into a range of 0.0 to 1.0
float tremolo = (lilka::fSin360(time * tremoloFrequency * 360) + 1.0f) / 2.0f;

// Apply the tremolo
*amplitude = *amplitude * (1.0f - tremolo * tremoloDepth / 15.0f);
}

void effect_volume_slide(float time, float relTime, float* frequency, float* amplitude, float* phase, uint8_t param) {
// This effect slides the volume of the note.
// If upper nibble is 0, lower nibble is slide down speed (1s / value)
// If lower nibble is 0, upper nibble is slide up speed (1s / value)
// relTime is the relative time of when the effect started

(void)time;
(void)frequency;
(void)phase;

uint8_t slideUpSpeed = (param & 0xF0) >> 4;
uint8_t slideDownSpeed = param & 0x0F;

float newAmplitude = *amplitude;

if (slideUpSpeed == 0) {
// Slide down
newAmplitude = 1.0f - (relTime / (1.0f / slideDownSpeed));
} else if (slideDownSpeed == 0) {
// Slide up
newAmplitude = relTime / (1.0f / slideUpSpeed);
}

// Clamp the amplitude
// TODO: We should probably override the amplitude, and disable this effect if event volume is set in tracker?
*amplitude *= fminf(fmaxf(newAmplitude, 0.0f), 1.0f);
}
61 changes: 61 additions & 0 deletions firmware/keira/src/apps/liltracker/effects.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#pragma once

#include <stdint.h>

typedef enum {
EFFECT_TYPE_NONE,
EFFECT_TYPE_ARPEGGIO, // NES: 00xy
EFFECT_TYPE_VIBRATO, // NES: 04xy
EFFECT_TYPE_TREMOLO, // NES: 07xy
EFFECT_TYPE_VOLUME_SLIDE, // NES: 0Axy
EFFECT_TYPE_COUNT,
} effect_type_t;

const effect_type_t effects[EFFECT_TYPE_COUNT] = {
EFFECT_TYPE_NONE,
EFFECT_TYPE_ARPEGGIO,
EFFECT_TYPE_VIBRATO,
EFFECT_TYPE_TREMOLO,
EFFECT_TYPE_VOLUME_SLIDE,
};

const char effect_signs[EFFECT_TYPE_COUNT] = {
'.',
'A',
'V',
'T',
'S',
};

typedef struct {
effect_type_t type;
uint8_t param;
} effect_t;

typedef void (*effect_fn_t)(
const float time, const float relTime, float* frequency, float* amplitude, float* phase, uint8_t param
);

void effect_none(
const float time, const float relTime, float* frequency, float* amplitude, float* phase, uint8_t param
);
void effect_arpeggio(
const float time, const float relTime, float* frequency, float* amplitude, float* phase, uint8_t param
);
void effect_vibrato(
const float time, const float relTime, float* frequency, float* amplitude, float* phase, uint8_t param
);
void effect_tremolo(
const float time, const float relTime, float* frequency, float* amplitude, float* phase, uint8_t param
);
void effect_volume_slide(
const float time, const float relTime, float* frequency, float* amplitude, float* phase, uint8_t param
);

const effect_fn_t effect_functions[EFFECT_TYPE_COUNT] = {
effect_none,
effect_arpeggio,
effect_vibrato,
effect_tremolo,
effect_volume_slide,
};
Loading

0 comments on commit f4e668a

Please sign in to comment.