Compare commits
No commits in common. "d2d8a9882a9ec6ef3e0057467982f22afd7967e7" and "8b072db7335cdcd6e05c282afbf07b22bff7863d" have entirely different histories.
d2d8a9882a
...
8b072db733
|
|
@ -1,7 +1,7 @@
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
typedef int32_t (*FUN)(int32_t);
|
#include <function.hpp>
|
||||||
|
|
||||||
int32_t stretch(FUN f, float multiplicator, int32_t value) {
|
auto simplest_lowpass(Function<uint32_t, int16_t> f_in) {
|
||||||
return f(multiplicator * value);
|
Function<uint32_t, int16_t> f_out;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,15 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
template<int32_t period, int32_t max_val>
|
template<uint32_t period, int16_t max_val>
|
||||||
int32_t sine(int32_t t) {
|
int16_t sine(uint32_t t) {
|
||||||
// 0 <= t < period is 0 <= t_2pi < 2 pi
|
// 0 <= t < period is 0 <= t_2pi < 2 pi
|
||||||
t %= period;
|
float t_2pi = 2 * M_PI / static_cast<float>(period) * t;
|
||||||
float t_2pi = 2 * M_PI / static_cast<float>(period) * t;
|
return static_cast<int16_t>(sinf(t_2pi) * max_val);
|
||||||
return static_cast<int32_t>(sinf(t_2pi) * max_val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<int32_t period, int32_t max_val>
|
template<uint32_t period, int16_t max_val>
|
||||||
int32_t square(int32_t t) {
|
int16_t square(uint32_t t) {
|
||||||
t %= period;
|
|
||||||
if (t <= period / 2) {
|
if (t <= period / 2) {
|
||||||
return -max_val;
|
return -max_val;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -19,12 +17,11 @@ int32_t square(int32_t t) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<int32_t period, int32_t max_val>
|
template<uint32_t period, int16_t max_val>
|
||||||
int32_t sawtooth(int32_t t) {
|
int16_t sawtooth(uint32_t t) {
|
||||||
// f(t) = a t + y
|
// f(t) = a t + y
|
||||||
// f(0) = -max_val = y
|
// f(0) = -max_val = y
|
||||||
// f(period) = a * period - max_val = max_val
|
// f(period) = a * period - max_val = max_val
|
||||||
// a = 2 * max_val / period
|
// a = 2 * max_val / period
|
||||||
t %= period;
|
|
||||||
return 2 * max_val * t / period - max_val;
|
return 2 * max_val * t / period - max_val;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
69
src/main.cpp
69
src/main.cpp
|
|
@ -5,67 +5,44 @@
|
||||||
|
|
||||||
constexpr int DAC_PIN = A2;
|
constexpr int DAC_PIN = A2;
|
||||||
|
|
||||||
constexpr uint32_t SAMPLING_RATE_HZ = 44100;
|
constexpr uint16_t SAMPLING_RATE_HZ = 8000;
|
||||||
|
|
||||||
constexpr uint32_t SAMPLE_US = 1000000 / SAMPLING_RATE_HZ;
|
constexpr unsigned long SAMPLE_US = 1000000 / SAMPLING_RATE_HZ;
|
||||||
|
|
||||||
|
#ifndef LED_BUILTIN
|
||||||
|
#define LED_BUILTIN PC13
|
||||||
|
#endif
|
||||||
|
|
||||||
unsigned long last_time_us = 0;
|
unsigned long last_time_us = 0;
|
||||||
|
|
||||||
int32_t sample, next_sample;
|
int16_t val;
|
||||||
int32_t i = 0;
|
|
||||||
int32_t sample_count = 0;
|
|
||||||
|
|
||||||
bool next_sample_computed = false;
|
bool sample_computed = false;
|
||||||
|
|
||||||
constexpr uint32_t hz_to_micros(uint32_t hz) {
|
constexpr uint32_t hz_to_micros(uint32_t hz) {
|
||||||
return 1000000 / hz;
|
return 1000000 / hz;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr uint32_t mhz_to_micros(uint32_t mhz) {
|
|
||||||
return 1000 * hz_to_micros(mhz);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<int32_t min, int32_t max>
|
|
||||||
constexpr int32_t shift_and_restrict(int32_t val) {
|
|
||||||
val += (max - min) / 2 + 1;
|
|
||||||
if (val < min) {
|
|
||||||
val = min;
|
|
||||||
}
|
|
||||||
if (val > max) {
|
|
||||||
val = max;
|
|
||||||
}
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
void writeVal(int32_t val) {
|
|
||||||
val = shift_and_restrict<0, 255>(val);
|
|
||||||
analogWrite(DAC_PIN, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
delay(1000);
|
delay(3000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
static int32_t note = -56;
|
|
||||||
unsigned long time_us = micros();
|
unsigned long time_us = micros();
|
||||||
uint32_t delta = time_us - last_time_us;
|
unsigned long delta = time_us - last_time_us;
|
||||||
if (!next_sample_computed) {
|
if (!sample_computed) {
|
||||||
constexpr uint32_t period = hz_to_micros(440);
|
if (delta < SAMPLE_US) {
|
||||||
next_sample = stretch(sine<period, 127>, powf(2, note / 12.0), time_us);
|
constexpr uint32_t period = hz_to_micros(412);
|
||||||
next_sample_computed = true;
|
val = sine<period, 512>(time_us % period);
|
||||||
}
|
sample_computed = true;
|
||||||
if (delta >= SAMPLE_US) {
|
|
||||||
last_time_us = time_us;
|
|
||||||
writeVal(next_sample);
|
|
||||||
next_sample_computed = false;
|
|
||||||
++sample_count;
|
|
||||||
}
|
|
||||||
if (16 * sample_count >= SAMPLING_RATE_HZ) {
|
|
||||||
sample_count = 0;
|
|
||||||
++note;
|
|
||||||
if (note > 12) {
|
|
||||||
note = -56;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
if (delta >= SAMPLE_US) {
|
||||||
|
last_time_us = time_us;
|
||||||
|
analogWrite(DAC_PIN, val);
|
||||||
|
sample_computed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delayMicroseconds(1);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue