generate MIDI pitch lookup table
This commit is contained in:
parent
636f18d70d
commit
adb9d5444b
|
@ -1,2 +1,3 @@
|
||||||
.vscode
|
.vscode
|
||||||
out
|
out
|
||||||
|
pitch_table.h
|
7
Makefile
7
Makefile
|
@ -88,7 +88,7 @@ endef
|
||||||
mkdir -p .vscode
|
mkdir -p .vscode
|
||||||
sed 's@__includePaths__@$(call to-json-array, ${AVR_INC} ${VPATH} ${VARIANTS})@' c_cpp_properties.json.template > .vscode/c_cpp_properties.json
|
sed 's@__includePaths__@$(call to-json-array, ${AVR_INC} ${VPATH} ${VARIANTS})@' c_cpp_properties.json.template > .vscode/c_cpp_properties.json
|
||||||
|
|
||||||
.PHONY: all clean upload vscode
|
.PHONY: all clean upload vscode pitch_table
|
||||||
|
|
||||||
all: ${BUILD_DIR}/${PROGRAM}.hex
|
all: ${BUILD_DIR}/${PROGRAM}.hex
|
||||||
|
|
||||||
|
@ -103,4 +103,7 @@ endif
|
||||||
|
|
||||||
vscode:
|
vscode:
|
||||||
rm -rf .vscode/c_cpp_properties.json
|
rm -rf .vscode/c_cpp_properties.json
|
||||||
make .vscode/c_cpp_properties.json
|
make .vscode/c_cpp_properties.json
|
||||||
|
|
||||||
|
pitch_table:
|
||||||
|
python gen_pitch_table.py > pitch_table.h
|
|
@ -0,0 +1,37 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
start_pitch = 36 # C2
|
||||||
|
end_pitch = 84 # C6
|
||||||
|
|
||||||
|
pitch_A0 = 21
|
||||||
|
pitch_C1 = 24
|
||||||
|
pitch_A4 = 69
|
||||||
|
freq_A4 = 440
|
||||||
|
|
||||||
|
def pitch_to_freq(pitch):
|
||||||
|
dist_A4 = pitch - pitch_A4
|
||||||
|
factor = pow(2, abs(dist_A4) / 12)
|
||||||
|
|
||||||
|
if dist_A4 > 0:
|
||||||
|
return freq_A4 * factor
|
||||||
|
else:
|
||||||
|
return freq_A4 / factor
|
||||||
|
|
||||||
|
def pitch_to_period_micros(pitch):
|
||||||
|
return 1 / pitch_to_freq(pitch) * 1000 * 1000
|
||||||
|
|
||||||
|
pitch_names = ["A", "A#", "B", "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#"]
|
||||||
|
def pitch_to_name(pitch):
|
||||||
|
return pitch_names[(pitch - pitch_A0) % 12] + str(int((pitch - pitch_C1) / 12) + 1)
|
||||||
|
|
||||||
|
print("#pragma once")
|
||||||
|
print("")
|
||||||
|
print("constexpr unsigned int midi_pitch_offset = " + str(start_pitch) + ";")
|
||||||
|
print("constexpr unsigned int midi_pitch_max = " + str(end_pitch) + ";")
|
||||||
|
print("constexpr unsigned long midi_pitch_period[" + str(end_pitch - start_pitch) + "] = {")
|
||||||
|
|
||||||
|
for i in range(start_pitch, end_pitch):
|
||||||
|
period = int(pitch_to_period_micros(i))
|
||||||
|
print(" " + str(period) + ",\t// " + pitch_to_name(i))
|
||||||
|
|
||||||
|
print("};")
|
18
main.cpp
18
main.cpp
|
@ -33,25 +33,15 @@ int main() {
|
||||||
motors[i].Init();
|
motors[i].Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test: play A4 (440 Hz) on each successive motor every second
|
// Test: play a C chord
|
||||||
int cur_motor = -1;
|
motors[0].TickAtPitch(60); // C4
|
||||||
|
motors[1].TickAtPitch(64); // E4
|
||||||
|
motors[2].TickAtPitch(67); // G4
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
unsigned long cur_micros = micros();
|
unsigned long cur_micros = micros();
|
||||||
|
|
||||||
handle_tick(cur_micros);
|
handle_tick(cur_micros);
|
||||||
|
|
||||||
int new_motor = (cur_micros / 1000 / 1000) % 4;
|
|
||||||
|
|
||||||
if (new_motor != cur_motor) {
|
|
||||||
motors[new_motor].TickOn(2272);
|
|
||||||
|
|
||||||
if (cur_motor != -1) {
|
|
||||||
motors[cur_motor].TickOff();
|
|
||||||
}
|
|
||||||
|
|
||||||
cur_motor = new_motor;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "motor_control.h"
|
#include "motor_control.h"
|
||||||
|
#include "pitch_table.h"
|
||||||
|
|
||||||
MotorControl::MotorControl(int pin_dir, int pin_step) :
|
MotorControl::MotorControl(int pin_dir, int pin_step) :
|
||||||
pin_dir(pin_dir), pin_step(pin_step),
|
pin_dir(pin_dir), pin_step(pin_step),
|
||||||
|
@ -22,6 +23,15 @@ void MotorControl::TickOn(unsigned long period_micros) {
|
||||||
last_tick_micros = 0;
|
last_tick_micros = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MotorControl::TickAtPitch(unsigned int midi_pitch) {
|
||||||
|
// Bounds check
|
||||||
|
if (midi_pitch < midi_pitch_offset || midi_pitch >= midi_pitch_max) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
TickOn(midi_pitch_period[midi_pitch - midi_pitch_offset]);
|
||||||
|
}
|
||||||
|
|
||||||
void MotorControl::TickOff() {
|
void MotorControl::TickOff() {
|
||||||
tick_period_micros = 0;
|
tick_period_micros = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,8 @@ class MotorControl {
|
||||||
void Init();
|
void Init();
|
||||||
// Set the motor to tick at a given interval (inverse of frequency)
|
// Set the motor to tick at a given interval (inverse of frequency)
|
||||||
void TickOn(unsigned long period_micros);
|
void TickOn(unsigned long period_micros);
|
||||||
|
// Set the motor to tick with a given MIDI pitch
|
||||||
|
void TickAtPitch(unsigned int midi_pitch);
|
||||||
// Turn off the motor
|
// Turn off the motor
|
||||||
void TickOff();
|
void TickOff();
|
||||||
// Perform a tick if necessary
|
// Perform a tick if necessary
|
||||||
|
|
Loading…
Reference in New Issue