Initial commit of Arduino libraries

This commit is contained in:
Sam
2025-05-23 10:47:41 +10:00
commit 5bfce5fc3e
2476 changed files with 1108481 additions and 0 deletions

View File

@@ -0,0 +1,289 @@
// Based on works and code by Shawn Silverman.
#include <stdint.h>
#include "fl/namespace.h"
#include "fl/wave_simulation.h"
namespace {
uint8_t half_duplex_blend_sqrt_q15(uint16_t x) {
x = MIN(x, 32767); // Q15
const int Q = 15;
uint32_t X = (uint32_t)x << Q; // promote to Q30
uint32_t y = (1u << Q); // start at “1.0” in Q15
// 34 iterations is plenty for 15bit precision:
for (int i = 0; i < 4; i++) {
y = ( y + (X / y) ) >> 1;
}
return static_cast<int16_t>(y) >> 8;
}
uint8_t half_duplex_blend_linear(uint16_t x) {
x = MIN(x, 32767); // Q15
x *= 2;
return x >> 8;
}
} // namespace
namespace fl {
void WaveSimulation2D::setSpeed(float speed) { sim->setSpeed(speed); }
WaveSimulation2D::WaveSimulation2D(uint32_t W, uint32_t H, SuperSample factor,
float speed, float dampening) {
init(W, H, factor, speed, dampening);
}
void WaveSimulation2D::init(uint32_t width, uint32_t height, SuperSample factor, float speed, int dampening) {
outerWidth = width;
outerHeight = height;
multiplier = static_cast<uint32_t>(factor);
sim.reset(new WaveSimulation2D_Real(width * multiplier, height * multiplier, speed, dampening));
// Extra frames are needed because the simulation slows down in
// proportion to the supersampling factor.
extraFrames = uint8_t(factor) - 1;
}
void WaveSimulation2D::setDampening(int damp) { sim->setDampening(damp); }
int WaveSimulation2D::getDampenening() const { return sim->getDampenening(); }
float WaveSimulation2D::getSpeed() const { return sim->getSpeed(); }
float WaveSimulation2D::getf(size_t x, size_t y) const {
if (!has(x, y))
return 0.0f;
float sum = 0.0f;
for (uint32_t j = 0; j < multiplier; ++j) {
for (uint32_t i = 0; i < multiplier; ++i) {
sum += sim->getf(x * multiplier + i, y * multiplier + j);
}
}
return sum / static_cast<float>(multiplier * multiplier);
}
int16_t WaveSimulation2D::geti16(size_t x, size_t y) const {
if (!has(x, y))
return 0;
int32_t sum = 0;
for (uint32_t j = 0; j < multiplier; ++j) {
for (uint32_t i = 0; i < multiplier; ++i) {
sum += sim->geti16(x * multiplier + i, y * multiplier + j);
}
}
return static_cast<int16_t>(sum / (multiplier * multiplier));
}
int16_t WaveSimulation2D::geti16Previous(size_t x, size_t y) const {
if (!has(x, y))
return 0;
int32_t sum = 0;
for (uint32_t j = 0; j < multiplier; ++j) {
for (uint32_t i = 0; i < multiplier; ++i) {
sum += sim->geti16Previous(x * multiplier + i, y * multiplier + j);
}
}
return static_cast<int16_t>(sum / (multiplier * multiplier));
}
bool WaveSimulation2D::geti16All(size_t x, size_t y, int16_t *curr,
int16_t *prev, int16_t *diff) const {
if (!has(x, y))
return false;
*curr = geti16(x, y);
*prev = geti16Previous(x, y);
*diff = *curr - *prev;
return true;
}
int8_t WaveSimulation2D::geti8(size_t x, size_t y) const {
return static_cast<int8_t>(geti16(x, y) >> 8);
}
uint8_t WaveSimulation2D::getu8(size_t x, size_t y) const {
int16_t value = geti16(x, y);
if (sim->getHalfDuplex()) {
uint16_t v2 = static_cast<uint16_t>(value);
switch (mU8Mode) {
case WAVE_U8_MODE_LINEAR:
return half_duplex_blend_linear(v2);
case WAVE_U8_MODE_SQRT:
return half_duplex_blend_sqrt_q15(v2);
}
}
return static_cast<uint8_t>(((static_cast<uint16_t>(value) + 32768)) >> 8);
}
bool WaveSimulation2D::has(size_t x, size_t y) const {
return (x < outerWidth) && (y < outerHeight);
}
void WaveSimulation2D::seti16(size_t x, size_t y, int16_t v16) {
if (!has(x, y))
return;
// radius in pixels of your diamond
int rad = static_cast<int>(multiplier) / 2;
for (size_t j = 0; j < multiplier; ++j) {
for (size_t i = 0; i < multiplier; ++i) {
// compute offset from the center of this block
int dx = static_cast<int>(i) - rad;
int dy = static_cast<int>(j) - rad;
// keep only those points whose Manhattan distance ≤ rad
if (ABS(dx) + ABS(dy) > rad)
continue;
size_t xx = x * multiplier + i;
size_t yy = y * multiplier + j;
if (sim->has(xx, yy)) {
sim->seti16(xx, yy, v16);
}
}
}
}
void WaveSimulation2D::setf(size_t x, size_t y, float value) {
if (!has(x, y))
return;
int16_t v16 = wave_detail::float_to_fixed(value);
seti16(x, y, v16);
}
void WaveSimulation2D::update() {
sim->update();
for (uint8_t i = 0; i < extraFrames; ++i) {
sim->update();
}
}
uint32_t WaveSimulation2D::getWidth() const { return outerWidth; }
uint32_t WaveSimulation2D::getHeight() const { return outerHeight; }
void WaveSimulation2D::setExtraFrames(uint8_t extra) { extraFrames = extra; }
WaveSimulation1D::WaveSimulation1D(uint32_t length, SuperSample factor,
float speed, int dampening) {
init(length, factor, speed, dampening);
}
void WaveSimulation1D::init(uint32_t length, SuperSample factor,
float speed, int dampening) {
outerLength = length;
multiplier = static_cast<uint32_t>(factor);
sim.reset(new WaveSimulation1D_Real(length * multiplier, speed, dampening));
// Extra updates (frames) are applied because the simulation slows down in
// proportion to the supersampling factor.
extraFrames = static_cast<uint8_t>(factor) - 1;
}
void WaveSimulation1D::setSpeed(float speed) { sim->setSpeed(speed); }
void WaveSimulation1D::setDampening(int damp) { sim->setDampening(damp); }
int WaveSimulation1D::getDampenening() const { return sim->getDampenening(); }
void WaveSimulation1D::setExtraFrames(uint8_t extra) { extraFrames = extra; }
float WaveSimulation1D::getSpeed() const { return sim->getSpeed(); }
float WaveSimulation1D::getf(size_t x) const {
if (!has(x))
return 0.0f;
float sum = 0.0f;
for (uint32_t i = 0; i < multiplier; ++i) {
sum += sim->getf(x * multiplier + i);
}
return sum / static_cast<float>(multiplier);
}
int16_t WaveSimulation1D::geti16(size_t x) const {
if (!has(x))
return 0;
int32_t sum = 0;
for (uint32_t i = 0; i < multiplier; ++i) {
sum += sim->geti16(x * multiplier + i);
}
return static_cast<int16_t>(sum / multiplier);
}
int16_t WaveSimulation1D::geti16Previous(size_t x) const {
if (!has(x))
return 0;
int32_t sum = 0;
for (uint32_t i = 0; i < multiplier; ++i) {
sum += sim->geti16Previous(x * multiplier + i);
}
return static_cast<int16_t>(sum / multiplier);
}
bool WaveSimulation1D::geti16All(size_t x, int16_t *curr, int16_t *prev,
int16_t *diff) const {
if (!has(x))
return false;
*curr = geti16(x);
*prev = geti16Previous(x);
*diff = *curr - *prev;
return true;
}
int8_t WaveSimulation1D::geti8(size_t x) const {
return static_cast<int8_t>(geti16(x) >> 8);
}
// uint8_t WaveSimulation2D::getu8(size_t x, size_t y) const {
// int16_t value = geti16(x, y);
// if (sim->getHalfDuplex()) {
// uint16_t v2 = static_cast<uint16_t>(value);
// switch (mU8Mode) {
// case WAVE_U8_MODE_LINEAR:
// return half_duplex_blend_linear(v2);
// case WAVE_U8_MODE_SQRT:
// return half_duplex_blend_sqrt_q15(v2);
// }
// }
// return static_cast<uint8_t>(((static_cast<uint16_t>(value) + 32768)) >> 8);
// }
uint8_t WaveSimulation1D::getu8(size_t x) const {
int16_t value = geti16(x);
if (sim->getHalfDuplex()) {
uint16_t v2 = static_cast<uint16_t>(value);
switch (mU8Mode) {
case WAVE_U8_MODE_LINEAR:
return half_duplex_blend_linear(v2);
case WAVE_U8_MODE_SQRT:
return half_duplex_blend_sqrt_q15(v2);
}
}
return static_cast<uint8_t>(((static_cast<uint16_t>(value) + 32768)) >> 8);
}
bool WaveSimulation1D::has(size_t x) const { return (x < outerLength); }
void WaveSimulation1D::setf(size_t x, float value) {
if (!has(x))
return;
for (uint32_t i = 0; i < multiplier; ++i) {
sim->set(x * multiplier + i, value);
}
}
void WaveSimulation1D::update() {
sim->update();
for (uint8_t i = 0; i < extraFrames; ++i) {
sim->update();
}
}
uint32_t WaveSimulation1D::getLength() const { return outerLength; }
} // namespace fl