motor_control: refactor: Extract TickController logic

While we are at it, fix the MIDI bend implementation so that it doesn't
reset every time a new note is played.
This commit is contained in:
Peter Cai 2021-06-30 19:43:24 +08:00
parent 606015ee5a
commit 6efea4f89d
2 changed files with 64 additions and 24 deletions

View File

@ -1,12 +1,45 @@
#include <Arduino.h>
#include <midi_Defs.h>
#include <eRCaGuy_Timer2_Counter.h>
#include "motor_control.h"
#include "./pitch_table.h"
TickController::TickController() :
midi_bend(8192), period_half_micros(0), period_with_bend(0) {
}
void TickController::SetPeriod(unsigned int half_micros) {
period_half_micros = half_micros;
CalculatePeriod();
}
void TickController::SetBend(unsigned int bend) {
if (bend >= 16384) {
return;
}
midi_bend = bend;
CalculatePeriod();
}
void TickController::CalculatePeriod() {
if (period_half_micros == 0) {
period_with_bend = 0;
return;
}
// Scale the MIDI bend value down to 0 - 2047
unsigned int _bend = midi_bend / 8;
period_with_bend = (unsigned int) (((float) period_half_micros) * pgm_read_float_near(midi_pitch_bend_scale + _bend));
}
unsigned int TickController::GetTruePeriod() {
return period_with_bend;
}
MotorControl::MotorControl(int pin_dir, int pin_step) :
pin_dir(pin_dir), pin_step(pin_step),
last_tick_half_micros(0), tick_period_half_micros(0),
tick_period_orig_half_micros(0)
last_tick_half_micros(0)
{
// No actual constructor logic -- initialization is in Init()
}
@ -20,9 +53,8 @@ void MotorControl::Init() {
}
void MotorControl::TickOn(unsigned long period_half_micros) {
tick_period_half_micros = period_half_micros;
tick_period_orig_half_micros = period_half_micros;
// Force the next tick to happen
tick_ctrl.SetPeriod(period_half_micros);
// Force a tick
last_tick_half_micros = 0;
}
@ -41,29 +73,22 @@ void MotorControl::TickPitchBend(int bend) {
bend = bend - MIDI_PITCHBEND_MIN;
if (bend < 0 || bend >= 16384) return;
if (tick_period_orig_half_micros == 0) return;
// Scale the MIDI bend value down to 0 - 2047
bend = bend / 8;
tick_period_half_micros = (unsigned long) (((float) tick_period_orig_half_micros) * pgm_read_float_near(midi_pitch_bend_scale + bend));
tick_ctrl.SetBend(bend);
}
void MotorControl::TickOff() {
tick_period_half_micros = 0;
tick_period_orig_half_micros = 0;
tick_ctrl.SetPeriod(0);
}
void MotorControl::Tick(unsigned long cur_half_micros) {
if (cur_half_micros == 0) {
unsigned long period = tick_ctrl.GetTruePeriod();
if (period == 0) {
return;
}
if (tick_period_half_micros == 0) {
return;
}
if (last_tick_half_micros == 0 || (cur_half_micros - last_tick_half_micros) >= tick_period_half_micros) {
if (last_tick_half_micros == 0 || cur_half_micros >= last_tick_half_micros + period) {
DoTick();
last_tick_half_micros = cur_half_micros;
}

View File

@ -1,15 +1,30 @@
#pragma once
class TickController {
private:
// 0 to disable
unsigned int period_half_micros;
// 0 - 16384, 8192 = no bend
unsigned int midi_bend;
unsigned int period_with_bend;
void CalculatePeriod();
public:
TickController();
void SetPeriod(unsigned int half_micros);
void SetBend(unsigned int bend);
// In units of half microseconds
// 0 = disabled
unsigned int GetTruePeriod();
};
class MotorControl {
private:
// Control pins of the stepper motor
int pin_dir, pin_step;
// Timestamp of the last motor tick
unsigned long last_tick_half_micros;
// Interval of motor ticking; 0 to disable the motor
unsigned long tick_period_half_micros;
// Original period of motor ticking (without applying bend)
unsigned long tick_period_orig_half_micros;
TickController tick_ctrl;
void DoTick();
public: