Reorganized file structure to allow building Arduino project

This commit is contained in:
Dejvino
2026-02-28 21:49:17 +01:00
parent ef69701878
commit aaeaa9986e
10 changed files with 391 additions and 224 deletions
+178 -3
View File
@@ -37,8 +37,8 @@ SynthEngine::SynthEngine(uint32_t sampleRate)
}
SynthEngine::~SynthEngine() {
for (int x = 0; x < 5; ++x) {
for (int y = 0; y < 8; ++y) {
for (int x = 0; x < GRID_W; ++x) {
for (int y = 0; y < GRID_H; ++y) {
if (grid[x][y].buffer) {
delete[] grid[x][y].buffer;
grid[x][y].buffer = nullptr;
@@ -47,6 +47,181 @@ SynthEngine::~SynthEngine() {
}
}
void SynthEngine::exportGrid(uint8_t* buffer) {
SynthLockGuard<SynthMutex> lock(gridMutex);
size_t idx = 0;
for(int y=0; y<GRID_H; ++y) {
for(int x=0; x<GRID_W; ++x) {
GridCell& c = grid[x][y];
buffer[idx++] = (uint8_t)c.type;
buffer[idx++] = (uint8_t)(c.param * 255.0f);
buffer[idx++] = (uint8_t)c.rotation;
}
}
}
void SynthEngine::importGrid(const uint8_t* buffer) {
SynthLockGuard<SynthMutex> lock(gridMutex);
size_t idx = 0;
for(int y=0; y<GRID_H; ++y) {
for(int x=0; x<GRID_W; ++x) {
GridCell& c = grid[x][y];
uint8_t t = buffer[idx++];
uint8_t p = buffer[idx++];
uint8_t r = buffer[idx++];
GridCell::Type newType = (GridCell::Type)t;
if (c.type != newType) {
if (c.buffer) { delete[] c.buffer; c.buffer = nullptr; c.buffer_size = 0; }
c.type = newType;
if (c.type == GridCell::DELAY || c.type == GridCell::REVERB || c.type == GridCell::PITCH_SHIFTER) {
c.buffer_size = 2 * _sampleRate;
c.buffer = new float[c.buffer_size]();
c.write_idx = 0;
}
}
c.param = (float)p / 255.0f;
c.rotation = r;
}
}
}
void SynthEngine::clearGrid() {
SynthLockGuard<SynthMutex> lock(gridMutex);
for (int x = 0; x < GRID_W; ++x) {
for (int y = 0; y < GRID_H; ++y) {
GridCell& c = grid[x][y];
if (c.type == GridCell::SINK) continue;
if (c.buffer) {
delete[] c.buffer;
c.buffer = nullptr;
c.buffer_size = 0;
}
c.type = GridCell::EMPTY;
c.param = 0.5f;
c.rotation = 0;
c.value = 0.0f;
c.phase = 0.0f;
}
}
}
void SynthEngine::loadPreset(int preset) {
clearGrid();
SynthLockGuard<SynthMutex> lock(gridMutex);
auto placeOp = [&](int x, int y, float ratio, float att, float rel) {
// Layout:
// (x, y) : G-IN (South)
// (x, y+1) : WIRE (East) -> Feeds envelope chain
// (x+1, y+1): ATT (East) ->
// (x+2, y+1): REL (East)
// (x+3, y+1): VCA (South) -> Output is here. Gets audio from OSC, gain from envelope.
// (x+3, y) : OSC (South) -> Audio source. Gets FM from its back (x+3, y-1).
grid[x][y].type = GridCell::GATE_INPUT; grid[x][y].rotation = 2; // S
grid[x][y+1].type = GridCell::WIRE; grid[x][y+1].rotation = 1; // E
grid[x+1][y+1].type = GridCell::ADSR_ATTACK; grid[x+1][y+1].rotation = 1; // E
grid[x+1][y+1].param = att;
grid[x+2][y+1].type = GridCell::ADSR_RELEASE; grid[x+2][y+1].rotation = 1; // E
grid[x+2][y+1].param = rel;
grid[x+3][y+1].type = GridCell::VCA; grid[x+3][y+1].rotation = 2; // S
grid[x+3][y+1].param = 0.0f; // Controlled by Env
grid[x+3][y].type = GridCell::INPUT_OSCILLATOR; grid[x+3][y].rotation = 2; // S
grid[x+3][y].param = (ratio > 1.0f) ? 0.5f : 0.0f;
};
int sinkY = GRID_H - 1;
int sinkX = GRID_W / 2;
if (preset == 1) { // Based on DX7 Algorithm 32
placeOp(0, 0, 1.0f, 0.01f, 0.5f); // Op 1
placeOp(4, 0, 1.0f, 0.05f, 0.3f); // Op 2
placeOp(8, 0, 2.0f, 0.01f, 0.2f); // Op 3
grid[3][2].type = GridCell::WIRE; grid[3][2].rotation = 2;
grid[3][3].type = GridCell::WIRE; grid[3][3].rotation = 1; // E
grid[4][3].type = GridCell::WIRE; grid[4][3].rotation = 1; // E
grid[5][3].type = GridCell::WIRE; grid[5][3].rotation = 1; // E
grid[6][3].type = GridCell::WIRE; grid[6][3].rotation = 2; // S
grid[7][2].type = GridCell::WIRE; grid[7][2].rotation = 2;
grid[7][3].type = GridCell::WIRE; grid[7][3].rotation = 3; // W
grid[11][2].type = GridCell::WIRE; grid[11][2].rotation = 2;
grid[11][3].type = GridCell::WIRE; grid[11][3].rotation = 3; // W
grid[10][3].type = GridCell::WIRE; grid[10][3].rotation = 3; // W
grid[9][3].type = GridCell::WIRE; grid[9][3].rotation = 3; // W
grid[8][3].type = GridCell::WIRE; grid[8][3].rotation = 3; // W
for(int y=4; y<sinkY; ++y) {
grid[6][y].type = GridCell::WIRE; grid[6][y].rotation = 2;
}
} else if (preset == 2) { // Algo 1: Stack (FM)
placeOp(4, 0, 2.0f, 0.01f, 0.2f); // Modulator
placeOp(4, 2, 1.0f, 0.01f, 0.8f); // Carrier
grid[7][4].type = GridCell::WIRE; grid[7][4].rotation = 3; // W
grid[6][4].type = GridCell::WIRE; grid[6][4].rotation = 2; // S
for(int y=5; y<sinkY; ++y) {
grid[6][y].type = GridCell::WIRE; grid[6][y].rotation = 2;
}
} else if (preset == 3) { // Algo 2
placeOp(4, 2, 1.0f, 0.01f, 0.8f);
placeOp(4, 0, 2.0f, 0.01f, 0.2f);
placeOp(0, 0, 1.0f, 0.01f, 0.5f);
grid[7][4].type = GridCell::WIRE; grid[7][4].rotation = 3; // W
grid[3][2].type = GridCell::WIRE; grid[3][2].rotation = 1; // E
grid[4][2].type = GridCell::WIRE; grid[4][2].rotation = 1; // E
grid[5][2].type = GridCell::WIRE; grid[5][2].rotation = 1; // E
grid[sinkX][2].type = GridCell::WIRE; grid[sinkX][2].rotation = 2; // S
grid[sinkX][3].type = GridCell::WIRE; grid[sinkX][3].rotation = 2; // S
grid[sinkX][4].type = GridCell::WIRE; grid[sinkX][4].rotation = 2; // S
for(int y=5; y<sinkY; ++y) {
grid[sinkX][y].type = GridCell::WIRE; grid[sinkX][y].rotation = 2;
}
} else if (preset == 4) { // Algo 4
placeOp(4, 4, 1.0f, 0.01f, 0.8f);
placeOp(4, 2, 2.0f, 0.01f, 0.2f);
placeOp(4, 0, 4.0f, 0.01f, 0.1f);
grid[7][6].type = GridCell::WIRE; grid[7][6].rotation = 3; // W
grid[sinkX][6].type = GridCell::WIRE; grid[sinkX][6].rotation = 2; // S
for(int y=7; y<sinkY; ++y) {
grid[sinkX][y].type = GridCell::WIRE; grid[sinkX][y].rotation = 2;
}
} else if (preset == 5) { // Algo 5
placeOp(4, 4, 1.0f, 0.01f, 0.8f);
placeOp(4, 2, 2.0f, 0.01f, 0.2f);
placeOp(4, 0, 4.0f, 0.01f, 0.1f);
placeOp(0, 0, 0.5f, 0.01f, 0.5f);
grid[7][6].type = GridCell::WIRE; grid[7][6].rotation = 3; // W
grid[3][2].type = GridCell::WIRE; grid[3][2].rotation = 2; // S
grid[3][3].type = GridCell::WIRE; grid[3][3].rotation = 1; // E
grid[4][3].type = GridCell::WIRE; grid[4][3].rotation = 1; // E
grid[5][3].type = GridCell::WIRE; grid[5][3].rotation = 1; // E
grid[6][3].type = GridCell::WIRE; grid[6][3].rotation = 2; // S
grid[sinkX][4].type = GridCell::WIRE; grid[sinkX][4].rotation = 2; // S
grid[sinkX][5].type = GridCell::WIRE; grid[sinkX][5].rotation = 2; // S
grid[sinkX][6].type = GridCell::WIRE; grid[sinkX][6].rotation = 2; // S
for(int y=7; y<sinkY; ++y) {
grid[sinkX][y].type = GridCell::WIRE; grid[sinkX][y].rotation = 2;
}
}
}
void SynthEngine::setFrequency(float freq) {
// Calculate the phase increment for a given frequency.
// The phase accumulator is a 32-bit unsigned integer (0 to 2^32-1).
@@ -525,7 +700,7 @@ float SynthEngine::processGridStep() {
void SynthEngine::process(int16_t* buffer, uint32_t numFrames) {
// Lock grid mutex to prevent UI from changing grid structure mid-process
std::lock_guard<std::mutex> lock(gridMutex);
SynthLockGuard<SynthMutex> lock(gridMutex);
for (uint32_t i = 0; i < numFrames; ++i) {
// The grid is now the primary sound source.