Reorganized file structure to allow building Arduino project
This commit is contained in:
+178
-3
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user