generate MIDI pitch lookup table
This commit is contained in:
parent
636f18d70d
commit
adb9d5444b
|
@ -1,2 +1,3 @@
|
|||
.vscode
|
||||
out
|
||||
out
|
||||
pitch_table.h
|
7
Makefile
7
Makefile
|
@ -88,7 +88,7 @@ endef
|
|||
mkdir -p .vscode
|
||||
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
|
||||
|
||||
|
@ -103,4 +103,7 @@ endif
|
|||
|
||||
vscode:
|
||||
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();
|
||||
}
|
||||
|
||||
// Test: play A4 (440 Hz) on each successive motor every second
|
||||
int cur_motor = -1;
|
||||
// Test: play a C chord
|
||||
motors[0].TickAtPitch(60); // C4
|
||||
motors[1].TickAtPitch(64); // E4
|
||||
motors[2].TickAtPitch(67); // G4
|
||||
|
||||
while (true) {
|
||||
unsigned long cur_micros = 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;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <Arduino.h>
|
||||
#include "motor_control.h"
|
||||
#include "pitch_table.h"
|
||||
|
||||
MotorControl::MotorControl(int pin_dir, int 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;
|
||||
}
|
||||
|
||||
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() {
|
||||
tick_period_micros = 0;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@ class MotorControl {
|
|||
void Init();
|
||||
// Set the motor to tick at a given interval (inverse of frequency)
|
||||
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
|
||||
void TickOff();
|
||||
// Perform a tick if necessary
|
||||
|
|
Loading…
Reference in New Issue