NoiceSynth/AudioThread.cpp

85 lines
2.6 KiB
C++

#include "AudioThread.h"
#include "SharedState.h"
#include <I2S.h>
#include <math.h>
// I2S Pin definitions
// You may need to change these to match your hardware setup (e.g., for a specific DAC).
const int I2S_BCLK_PIN = 9; // Bit Clock (GP9)
const int I2S_LRC_PIN = 10; // Left-Right Clock (GP10)
const int I2S_DOUT_PIN = 11; // Data Out (GP11)
// Audio parameters
const int SAMPLE_RATE = 44100;
const int16_t AMPLITUDE = 16383; // Use a lower amplitude to avoid clipping (max is 32767 for 16-bit)
// Create an I2S output object
I2S i2s(OUTPUT);
// --- Synthesizer State ---
float currentFrequency = 440.0f;
double phase = 0.0;
unsigned long lastNoteChangeTime = 0;
// ---
void setupAudio() {
// Configure I2S pins
i2s.setBCLK(I2S_BCLK_PIN);
i2s.setDATA(I2S_DOUT_PIN);
// Set the sample rate and start I2S communication
i2s.setFrequency(SAMPLE_RATE);
if (!i2s.begin()) {
Serial.println("Failed to initialize I2S!");
while (1); // Halt on error
}
// Seed the random number generator from an unconnected analog pin
randomSeed(analogRead(A0));
}
void loopAudio() {
unsigned long now = millis();
// Every 500ms, pick a new random note to play
if (now - lastNoteChangeTime > 500) {
lastNoteChangeTime = now;
int noteIndex = random(0, SCALES[currentScaleIndex].numNotes);
// Calculate frequency based on key, scale, and octave
const float baseFrequency = 261.63f; // C4
float keyFrequency = baseFrequency * pow(2.0f, currentKeyIndex / 12.0f);
int semitoneOffset = SCALES[currentScaleIndex].semitones[noteIndex];
currentFrequency = keyFrequency * pow(2.0f, semitoneOffset / 12.0f);
Serial.println("Playing note: " + String(currentFrequency) + " Hz");
}
// Generate the sine wave sample
int16_t sample;
double phaseIncrement = 2.0 * M_PI * currentFrequency / SAMPLE_RATE;
phase = fmod(phase + phaseIncrement, 2.0 * M_PI);
switch (currentWavetableIndex) {
case 0: // Sine
sample = static_cast<int16_t>(AMPLITUDE * sin(phase));
break;
case 1: // Square
sample = (phase < M_PI) ? AMPLITUDE : -AMPLITUDE;
break;
case 2: // Saw
sample = static_cast<int16_t>(AMPLITUDE * (1.0 - (phase / M_PI)));
break;
case 3: // Triangle
sample = static_cast<int16_t>(AMPLITUDE * (2.0 * fabs(phase / M_PI - 1.0) - 1.0));
break;
default:
sample = 0;
break;
}
// Write the same sample to both left and right channels (mono audio).
// This call is blocking and will wait until there is space in the DMA buffer.
i2s.write(sample);
i2s.write(sample);
}