now with sawtooth, square, and triangle waves :D
This commit is contained in:
parent
16254662b9
commit
ef747bad41
14
README.md
14
README.md
|
@ -20,12 +20,12 @@ This uses an AVR microcontroller (ATMega328P-PU).
|
||||||
|
|
||||||
# Instruction Set
|
# Instruction Set
|
||||||
|
|
||||||
| ID | Name | Size | Layout |
|
| ID | Name | Size | Layout |
|
||||||
|-|-|-|-|
|
|-|-|-|-|
|
||||||
| 0 | stop | 1 | id (3), empty (5) |
|
| 0 | stop | 1 | id (3), empty (5) |
|
||||||
| 1 | setup | 8 | id (3), us_per_tick (29), amplitude (8), size (24) |
|
| 1 | setup | 8 | id (3), us_per_tick (29), amplitude (8), size (24) |
|
||||||
| 2 | set | 3 | id (3), index (5), frequency (12), empty (4) |
|
| 2 | set | 3 | id (3), index (5), frequency (12), mode (2), empty (2) |
|
||||||
| 3 | set-ts | 5 | id (3), index (5), ticks (20), frequency (12) |
|
| 3 | set-ts | 5 | id (3), index (5), ticks (18), frequency (12), mode (2) |
|
||||||
| 4 | clear | 1 | id (3), index (5) |
|
| 4 | clear | 1 | id (3), index (5) |
|
||||||
| 5 | clear-ts | 4 | id (3), index (5), ticks (20), empty (4) |
|
| 5 | clear-ts | 4 | id (3), index (5), ticks (18), empty (6) |
|
||||||
|
|
||||||
|
|
18
entry.hpp
18
entry.hpp
|
@ -9,13 +9,14 @@ struct Checker {
|
||||||
namespace entry {
|
namespace entry {
|
||||||
|
|
||||||
enum Type : uint8_t {
|
enum Type : uint8_t {
|
||||||
stop = 0,
|
stop = 0,
|
||||||
config = 1,
|
config = 1,
|
||||||
set = 2,
|
set = 2,
|
||||||
set_ts = 3,
|
set_ts = 3,
|
||||||
clear = 4,
|
clear = 4,
|
||||||
clear_ts = 5,
|
clear_ts = 5,
|
||||||
tempo = 6,
|
set_saw = 6,
|
||||||
|
set_saw_ts = 7,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum NextType {
|
enum NextType {
|
||||||
|
@ -28,6 +29,7 @@ namespace entry {
|
||||||
uint8_t index;
|
uint8_t index;
|
||||||
uint8_t amplitude;
|
uint8_t amplitude;
|
||||||
uint16_t frequency;
|
uint16_t frequency;
|
||||||
|
uint8_t mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Tempo {
|
struct Tempo {
|
||||||
|
@ -47,8 +49,6 @@ namespace entry {
|
||||||
return 4;
|
return 4;
|
||||||
case Type::config:
|
case Type::config:
|
||||||
return 8;
|
return 8;
|
||||||
case Type::tempo:
|
|
||||||
return 7;
|
|
||||||
case Type::stop:
|
case Type::stop:
|
||||||
default:
|
default:
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -20,10 +20,7 @@ struct {
|
||||||
} config;
|
} config;
|
||||||
struct {
|
struct {
|
||||||
entry::NextType type = entry::nt_none;
|
entry::NextType type = entry::nt_none;
|
||||||
union {
|
entry::Tone tone;
|
||||||
entry::Tone tone;
|
|
||||||
entry::Tempo tempo;
|
|
||||||
};
|
|
||||||
} next;
|
} next;
|
||||||
|
|
||||||
void scheduler::reset() {
|
void scheduler::reset() {
|
||||||
|
@ -36,19 +33,12 @@ static void do_next() {
|
||||||
|
|
||||||
int i = 1;
|
int i = 1;
|
||||||
|
|
||||||
if(state == State::play) {
|
if(next.type == entry::nt_tone) {
|
||||||
switch(next.type) {
|
if(state == State::play) {
|
||||||
case entry::nt_tone:
|
tones::set(next.tone.index, next.tone.frequency, next.tone.amplitude, next.tone.mode);
|
||||||
tones::set(next.tone.index, next.tone.frequency, next.tone.amplitude);
|
|
||||||
break;
|
|
||||||
case entry::nt_tempo:
|
|
||||||
ts_init += next.tempo.ticks * config.us_per_tick;
|
|
||||||
tick_offset = next.tempo.ticks;
|
|
||||||
config.us_per_tick = next.tempo.us_per_tick;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
next.type = entry::nt_none;
|
||||||
}
|
}
|
||||||
next.type = entry::nt_none;
|
|
||||||
|
|
||||||
uint64_t v = 0;
|
uint64_t v = 0;
|
||||||
uint8_t buff[8];
|
uint8_t buff[8];
|
||||||
|
@ -80,7 +70,9 @@ static void do_next() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case entry::Type::set: {
|
case entry::Type::set: {
|
||||||
v >>= 4;
|
v >>= 2;
|
||||||
|
next.tone.mode = v & bm(2);
|
||||||
|
v >>= 2;
|
||||||
next.type = entry::nt_tone;
|
next.type = entry::nt_tone;
|
||||||
next.tone.frequency = v & bm(12);
|
next.tone.frequency = v & bm(12);
|
||||||
v >>= 12;
|
v >>= 12;
|
||||||
|
@ -90,10 +82,12 @@ static void do_next() {
|
||||||
}
|
}
|
||||||
case entry::Type::set_ts: {
|
case entry::Type::set_ts: {
|
||||||
next.type = entry::nt_tone;
|
next.type = entry::nt_tone;
|
||||||
|
next.tone.mode = v & bm(2);
|
||||||
|
v >>= 2;
|
||||||
next.tone.frequency = v & bm(12);
|
next.tone.frequency = v & bm(12);
|
||||||
v >>= 12;
|
v >>= 12;
|
||||||
uint32_t ticks = (v & bm(20)) - tick_offset;
|
uint32_t ticks = (v & bm(18)) - tick_offset;
|
||||||
v >>= 20;
|
v >>= 18;
|
||||||
next.tone.index = v & bm(5);
|
next.tone.index = v & bm(5);
|
||||||
next.tone.amplitude = config.amplitude;
|
next.tone.amplitude = config.amplitude;
|
||||||
timestamp = ticks * config.us_per_tick + ts_init;
|
timestamp = ticks * config.us_per_tick + ts_init;
|
||||||
|
@ -107,9 +101,9 @@ static void do_next() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case entry::Type::clear_ts: {
|
case entry::Type::clear_ts: {
|
||||||
v >>= 4;
|
v >>= 6;
|
||||||
uint32_t ticks = (v & bm(20)) - tick_offset;
|
uint32_t ticks = (v & bm(18)) - tick_offset;
|
||||||
v >>= 20;
|
v >>= 18;
|
||||||
next.type = entry::nt_tone;
|
next.type = entry::nt_tone;
|
||||||
next.tone.index = v & bm(5);
|
next.tone.index = v & bm(5);
|
||||||
next.tone.frequency = 0;
|
next.tone.frequency = 0;
|
||||||
|
|
4
tone.cpp
4
tone.cpp
|
@ -2,6 +2,10 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "tone.hpp"
|
#include "tone.hpp"
|
||||||
|
|
||||||
|
static int8_t abs(int8_t v) {
|
||||||
|
return v >= 0 ? v : -v;
|
||||||
|
}
|
||||||
|
|
||||||
void Tone::init() {
|
void Tone::init() {
|
||||||
for(unsigned i = 0; i < sizeof(sin_lookup); i++) {
|
for(unsigned i = 0; i < sizeof(sin_lookup); i++) {
|
||||||
sin_lookup[i] = round(sin((float)i / sizeof(sin_lookup) * M_PI * 2) * 127);
|
sin_lookup[i] = round(sin((float)i / sizeof(sin_lookup) * M_PI * 2) * 127);
|
||||||
|
|
28
tone.hpp
28
tone.hpp
|
@ -5,9 +5,18 @@
|
||||||
#include "util.hpp"
|
#include "util.hpp"
|
||||||
|
|
||||||
struct Tone {
|
struct Tone {
|
||||||
|
|
||||||
|
enum Type {
|
||||||
|
tt_sine = 0,
|
||||||
|
tt_saw = 1,
|
||||||
|
tt_square = 2,
|
||||||
|
tt_triangle = 3,
|
||||||
|
};
|
||||||
|
|
||||||
uint32_t phase;
|
uint32_t phase;
|
||||||
uint16_t frequency;
|
uint16_t frequency;
|
||||||
uint8_t amplitude;
|
uint8_t amplitude;
|
||||||
|
Type mode;
|
||||||
|
|
||||||
inline static int8_t sin_lookup[256];
|
inline static int8_t sin_lookup[256];
|
||||||
|
|
||||||
|
@ -22,8 +31,23 @@ struct Tone {
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int get() const AW_IN {
|
inline int get() const AW_IN {
|
||||||
uint8_t id = phase >> 12;
|
int v;
|
||||||
return (int)sin_lookup[id] * amplitude;
|
switch(mode) {
|
||||||
|
case tt_sine:
|
||||||
|
v = sin_lookup[(phase >> 12) & 255];
|
||||||
|
break;
|
||||||
|
case tt_saw:
|
||||||
|
v = (int8_t)((phase >> 12) & 255);
|
||||||
|
break;
|
||||||
|
case tt_square:
|
||||||
|
v = phase & 0x80000 ? -127 : 127;
|
||||||
|
break;
|
||||||
|
case tt_triangle:
|
||||||
|
v = (phase >> 11) & 0x1ff;
|
||||||
|
v = (v > 0xff ? 1 : -1) * (int8_t)phase;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return v * amplitude;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -40,16 +40,17 @@ void tones::clear_all() {
|
||||||
active = 0;
|
active = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tones::set(uint8_t index, uint16_t frequency, float amplitude) {
|
void tones::set(uint8_t index, uint16_t frequency, float amplitude, Tone::Type mode) {
|
||||||
if(index >= size(all)) {
|
if(index >= size(all)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Tone& t = all[lookup[index]];
|
Tone& t = all[lookup[index]];
|
||||||
if(amplitude == 0) {
|
if(amplitude == 0) {
|
||||||
t = {0, 0, 0};
|
t = {0, 0, 0, Tone::tt_sine};
|
||||||
} else {
|
} else {
|
||||||
t.frequency = frequency;
|
t.frequency = frequency;
|
||||||
t.amplitude = amplitude;
|
t.amplitude = amplitude;
|
||||||
|
t.mode = mode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,11 +9,10 @@ namespace tones {
|
||||||
inline Tone all[32];
|
inline Tone all[32];
|
||||||
inline uint8_t lookup[size(all)];
|
inline uint8_t lookup[size(all)];
|
||||||
inline uint8_t rlookup[size(all)];
|
inline uint8_t rlookup[size(all)];
|
||||||
|
|
||||||
inline int active;
|
inline int active;
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
void set(uint8_t index, uint16_t frequency, float amplitude);
|
void set(uint8_t index, uint16_t frequency, float amplitude, Tone::Type mode);
|
||||||
void clear_all();
|
void clear_all();
|
||||||
void recalc();
|
void recalc();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue