Merge pull request #32 from MrDham/MrDham-remove-float-calc

Mr dham remove float calc
master 2.9
MrDham 2 months ago committed by GitHub
commit 95ed81836f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 154
      Open_Theremin_V3/application.cpp
  2. 151
      Open_Theremin_V3/application.h
  3. 8
      README.md

@ -9,7 +9,8 @@
#include "EEPROM.h"
const AppMode AppModeValues[] = {MUTE,NORMAL};
const int16_t CalibrationTolerance = 15;
const int16_t PitchCalibrationTolerance = 15;
const int16_t VolumeCalibrationTolerance = 21;
const int16_t PitchFreqOffset = 700;
const int16_t VolumeFreqOffset = 700;
const int8_t HYST_VAL = 40;
@ -42,8 +43,8 @@ static uint16_t old_midi_bend = 0;
static uint8_t midi_bend_low;
static uint8_t midi_bend_high;
static double double_log_freq = 0;
static double midi_key_follow = 0.5;
static uint32_t long_log_note = 0;
static uint32_t midi_key_follow = 2048; ;
// Configuration parameters
static uint8_t registerValue = 2;
@ -57,12 +58,12 @@ static uint8_t flag_pitch_bend_on = 1;
static uint8_t loop_midi_cc = 7;
static uint8_t rod_midi_cc = 255;
static uint8_t rod_midi_cc_lo = 255;
static double rod_cc_scale = 1;
static uint32_t rod_cc_scale = 128;
// tweakable paramameters
#define VELOCITY_SENS 9 // How easy it is to reach highest velocity (127). Something betwen 5 and 12.
#define PLAYER_ACCURACY 0.2 // between 0 (very accurate players) and 0.5 (not accurate at all)
#define PLAYER_ACCURACY 819 // between 0 (very accurate players) and 2048 (not accurate at all)
static uint16_t data_pot_value = 0;
static uint16_t old_data_pot_value = 0;
@ -399,7 +400,7 @@ pitchfn1 = GetPitchMeasurement();
l_iteration_pitch = 0;
while ((abs(pitchfn0 - pitchfn1) > CalibrationTolerance) && (l_iteration_pitch < 12))
while ((abs(pitchfn0 - pitchfn1) > PitchCalibrationTolerance) && (l_iteration_pitch < 12))
{
SPImcpDAC2Asend(pitchXn0);
@ -469,7 +470,7 @@ volumefn1 = GetVolumeMeasurement();
l_iteration_volume = 0;
while ((abs(volumefn0 - volumefn1) > CalibrationTolerance) && (l_iteration_volume < 12))
while ((abs(volumefn0 - volumefn1) > VolumeCalibrationTolerance) && (l_iteration_volume < 12))
{
SPImcpDAC2Bsend(volumeXn0);
@ -496,6 +497,76 @@ EEPROM.put(2,volumeXn0);
}
// calculate log2 of an unsigned from 1 to 65535 into a 4.12 fixed point unsigned
// To avoid use of log (double) function
uint16_t Application::log2U16 (uint16_t lin_input)
{
uint32_t long_lin; // To turn input into a 16.16 fixed point
//unsigned long bit_pos;
uint32_t log_output; // 4.12 fixed point log calculation
int32_t long_x1;
int32_t long_x2;
int32_t long_x3;
const int32_t POLY_A0 = 37;
const int32_t POLY_A1 = 46390;
const int32_t POLY_A2 = -18778;
const int32_t POLY_A3 = 5155;
if (lin_input != 0)
{
long_lin = (uint32_t) (lin_input) << 16;
log_output = 0;
// Calculate integer part of log2 and reduce long_lin into 16.16 between 1 and 2
if (long_lin >= 16777216) // 2^(8 + 16)
{
log_output += 8 << 12;
long_lin = long_lin >> 8;
}
if (long_lin >= 1048576) // 2^(4 + 16)
{
log_output += 4 << 12;
long_lin = long_lin >> 4;
}
if (long_lin >= 262144) // 2^(2 + 16)
{
log_output += 2 << 12;
long_lin = long_lin >> 2;
}
if (long_lin >= 131072) // 2^(1 + 16)
{
log_output += 1 << 12;
long_lin = long_lin >> 1;
}
// long_lin is between 1 and 2 now (16.16 fixed point)
// Calculate 3rd degree polynomial approximation log(x)=Polynomial(x-1) in signed long s15.16 and reduce to unsigned 4.12 at the very end.
long_lin = long_lin >> 1; // reduce to 17.15 bit to support signed operations here after
long_x1 = long_lin-(32768); //(x-1) we have the decimal part in s15 now
long_x2 = (long_x1 * long_x1) >> 15 ; // (x-1)^2
long_x3 = (long_x2 * long_x1) >> 15 ; // (x-1)^3
log_output += ( (POLY_A0)
+ ((POLY_A1 * long_x1) >> 15)
+ ((POLY_A2 * long_x2) >> 15)
+ ((POLY_A3 * long_x3) >> 15) ) >> 3;
}
else
{
log_output=0;
}
return log_output;
}
void Application::hzToAddVal(float hz) {
setWavetableSampleAdvance((uint16_t)(hz * HZ_ADDVAL_FACTOR));
}
@ -561,41 +632,42 @@ void Application::midi_msg_send(uint8_t channel, uint8_t midi_cmd1, uint8_t midi
// The bigger is synth's pitch bend range the beter is the effect.
void Application::midi_application ()
{
double delta_loop_cc_val = 0;
double calculated_velocity = 0;
int16_t delta_loop_cc_val = 0;
int16_t calculated_velocity = 0;
// Calculate loop antena cc value for midi
new_midi_loop_cc_val = loop_hand_pos >> 1;
new_midi_loop_cc_val = min (new_midi_loop_cc_val, 127);
delta_loop_cc_val = (double)new_midi_loop_cc_val - (double)old_midi_loop_cc_val;
delta_loop_cc_val = (int16_t)new_midi_loop_cc_val - (int16_t)old_midi_loop_cc_val;
// Calculate log freq
if ((vPointerIncrement < 18) || (vPointerIncrement > 65518))
{
// Lowest note
double_log_freq = 0;
long_log_note = 0;
}
else if ((vPointerIncrement > 26315) && (vPointerIncrement < 39221))
{
// Highest note
double_log_freq = 127;
long_log_note = 127;
}
else if (vPointerIncrement < 32768)
{
// Positive frequencies
// Find note in the playing range
double_log_freq = (log (vPointerIncrement/17.152) / 0.057762265); // Precise note played in the logaritmic scale
// 16795 = log2U16 (C0 [8.1758] * HZ_ADDVAL_FACTOR [2.09785])
long_log_note = 12 * ((uint32_t) log2U16(vPointerIncrement) - 16795); // Precise note played in the logaritmic scale
}
else
{
// Negative frequencies
// Find note in the playing range
double_log_freq = (log ((65535-vPointerIncrement+1)/17.152) / 0.057762265); // Precise note played in the logaritmic scale
// 16795 = log2U16 (C0 [8.1758] * HZ_ADDVAL_FACTOR [2.09785])
long_log_note = 12 * ((uint32_t) log2U16(65535-vPointerIncrement+1) - 16795); // Precise note played in the logaritmic scale
}
// Calculate rod antena cc value for midi
new_midi_rod_cc_val = round (min(((double_log_freq * 128) * rod_cc_scale), 16383)); // 14 bit value !
new_midi_rod_cc_val = (uint16_t) min((long_log_note * rod_cc_scale) >> 12, 16383); // 14 bit value
// State machine for MIDI
switch (_midistate)
@ -637,7 +709,7 @@ void Application::midi_application ()
if (new_midi_loop_cc_val > midi_volume_trigger)
{
// Set key follow to the minimum in order to use closest note played as the center note
midi_key_follow = 0.5;
midi_key_follow = 2048;
// Calculate note and associated pitch bend
calculate_note_bend ();
@ -649,8 +721,8 @@ void Application::midi_application ()
// Calculate velocity
if (midi_timer != 0)
{
calculated_velocity = (64 * (127 - (double)midi_volume_trigger) / 127) + (VELOCITY_SENS * (double)midi_volume_trigger * delta_loop_cc_val / (double)midi_timer);
midi_velocity = min (round (abs (calculated_velocity)), 127);
calculated_velocity = ((127 - midi_volume_trigger) >> 1 ) + (VELOCITY_SENS * midi_volume_trigger * delta_loop_cc_val / midi_timer);
midi_velocity = min (abs (calculated_velocity), 127);
}
else
{
@ -710,12 +782,12 @@ void Application::midi_application ()
if ( flag_legato_on == 1)
{
// Set key follow so as next played note will be at limit of pitch bend range
midi_key_follow = (double)(midi_bend_range) - PLAYER_ACCURACY;
midi_key_follow = ((uint32_t) midi_bend_range * 4096) - PLAYER_ACCURACY;
}
else
{
// Set key follow to max so as no key follows
midi_key_follow = 127;
midi_key_follow = 520192; // 127*2^12
}
// Calculate note and associated pitch bend
@ -771,16 +843,16 @@ void Application::midi_application ()
void Application::calculate_note_bend ()
{
double double_log_bend;
double double_norm_log_bend;
int32_t long_log_bend;
int32_t long_norm_log_bend;
double_log_bend = double_log_freq - old_midi_note; // How far from last played midi chromatic note we are
long_log_bend = ((int32_t)long_log_note) - (((int32_t) old_midi_note) * 4096); // How far from last played midi chromatic note we are
// If too much far from last midi chromatic note played (midi_key_follow depends on pitch bend range)
if ((abs (double_log_bend) >= midi_key_follow) && (midi_key_follow != 127))
if ((abs (long_log_bend) >= midi_key_follow) && (midi_key_follow != 520192))
{
new_midi_note = round (double_log_freq); // Select the new midi chromatic note
double_log_bend = double_log_freq - new_midi_note; // calculate bend to reach precise note played
new_midi_note = (uint8_t) ((long_log_note + 2048) >> 12); // Select the new midi chromatic note - round to integer part by adding 1/2 before shifting
long_log_bend = ((int32_t) long_log_note) - (((int32_t) new_midi_note) * 4096); // calculate bend to reach precise note played
}
else
{
@ -791,16 +863,16 @@ void Application::calculate_note_bend ()
if (flag_pitch_bend_on == 1)
{
// use it to reach precise note played
double_norm_log_bend = (double_log_bend / midi_bend_range);
if (double_norm_log_bend > 1)
long_norm_log_bend = (long_log_bend / midi_bend_range);
if (long_norm_log_bend > 4096)
{
double_norm_log_bend = 1;
long_norm_log_bend = 4096;
}
else if (double_norm_log_bend < -1)
else if (long_norm_log_bend < -4096)
{
double_norm_log_bend = -1;
long_norm_log_bend = -4096;
}
new_midi_bend = 8192 + (8191 * double_norm_log_bend); // Calculate midi pitch bend
new_midi_bend = 8192 + ((long_norm_log_bend * 8191) >> 12); // Calculate midi pitch bend
}
else
{
@ -968,42 +1040,42 @@ void Application::set_parameters ()
case 0:
rod_midi_cc = 255; // Nothing
rod_midi_cc_lo = 255; // Nothing
rod_cc_scale = 1.0;
rod_cc_scale = 128;
break;
case 1:
rod_midi_cc = 8; // Balance
rod_midi_cc_lo = 255; // No least significant bits
rod_cc_scale = 1.0;
rod_cc_scale = 128;
break;
case 2:
rod_midi_cc = 10; // Pan
rod_midi_cc_lo = 255; // No least significant bits
rod_cc_scale = 1.0;
rod_cc_scale = 128;
break;
case 3:
rod_midi_cc = 16; // General Purpose 1 (14 Bits)
rod_midi_cc_lo = 48; // General Purpose 1 least significant bits
rod_cc_scale = 1.0;
rod_cc_scale = 128;
break;
case 4:
rod_midi_cc = 17; // General Purpose 2 (14 Bits)
rod_midi_cc_lo = 49; // General Purpose 2 least significant bits
rod_cc_scale = 1.0;
rod_cc_scale = 128;
break;
case 5:
rod_midi_cc = 18; // General Purpose 3 (7 Bits)
rod_midi_cc_lo = 255; // No least significant bits
rod_cc_scale = 1.0;
rod_cc_scale = 128;
break;
case 6:
rod_midi_cc = 19; // General Purpose 4 (7 Bits)
rod_midi_cc_lo = 255; // No least significant bits
rod_cc_scale = 1.0;
rod_cc_scale = 128;
break;
default:
rod_midi_cc = 74; // Cutoff (exists of both loop and rod)
rod_midi_cc_lo = 255; // No least significant bits
rod_cc_scale = 1.0;
rod_cc_scale = 128;
break;
}
break;

@ -1,76 +1,77 @@
#ifndef _APPLICATION_H
#define _APPLICATION_H
#include <avr/io.h>
#include "build.h"
enum AppState {CALIBRATING = 0, PLAYING};
enum AppMode {MUTE = 0, NORMAL};
enum AppMidiState {MIDI_SILENT = 0, MIDI_PLAYING, MIDI_STOP, MIDI_MUTE};
class Application {
public:
Application();
void setup();
void loop();
private:
static const uint16_t MAX_VOLUME = 4095;
static const uint32_t TRIM_PITCH_FACTOR = 33554432;
static const uint32_t FREQ_FACTOR = 1600000000;
static const int16_t BUTTON_PIN = 6;
static const int16_t LED_PIN_1 = 18;
static const int16_t LED_PIN_2 = 19;
static const int16_t PITCH_POT = 0;
static const int16_t VOLUME_POT = 1;
static const int16_t WAVE_SELECT_POT = 2;
static const int16_t REGISTER_SELECT_POT = 3;
AppState _state;
AppMode _mode;
AppMidiState _midistate;
void calibrate();
void calibrate_pitch();
void calibrate_volume();
AppMode nextMode();
void initialiseTimer();
void initialiseInterrupts();
void InitialisePitchMeasurement();
void InitialiseVolumeMeasurement();
unsigned long GetPitchMeasurement();
unsigned long GetVolumeMeasurement();
unsigned long GetQMeasurement();
const float HZ_ADDVAL_FACTOR = 2.09785;
const float MIDDLE_C = 261.6;
void playNote(float hz, uint16_t milliseconds, uint8_t volume);
void hzToAddVal(float hz);
void playStartupSound();
void playCalibratingCountdownSound();
void playModeSettingSound();
void delay_NOP(unsigned long time);
void midi_setup();
void midi_msg_send(uint8_t channel, uint8_t midi_cmd1, uint8_t midi_cmd2, uint8_t midi_value);
void midi_application ();
void calculate_note_bend ();
void init_parameters ();
void set_parameters ();
};
#ifndef _APPLICATION_H
#define _APPLICATION_H
#include <avr/io.h>
#include "build.h"
enum AppState {CALIBRATING = 0, PLAYING};
enum AppMode {MUTE = 0, NORMAL};
enum AppMidiState {MIDI_SILENT = 0, MIDI_PLAYING, MIDI_STOP, MIDI_MUTE};
class Application {
public:
Application();
void setup();
void loop();
private:
static const uint16_t MAX_VOLUME = 4095;
static const uint32_t TRIM_PITCH_FACTOR = 33554432;
static const uint32_t FREQ_FACTOR = 1600000000;
static const int16_t BUTTON_PIN = 6;
static const int16_t LED_PIN_1 = 18;
static const int16_t LED_PIN_2 = 19;
static const int16_t PITCH_POT = 0;
static const int16_t VOLUME_POT = 1;
static const int16_t WAVE_SELECT_POT = 2;
static const int16_t REGISTER_SELECT_POT = 3;
AppState _state;
AppMode _mode;
AppMidiState _midistate;
void calibrate();
void calibrate_pitch();
void calibrate_volume();
AppMode nextMode();
void initialiseTimer();
void initialiseInterrupts();
void InitialisePitchMeasurement();
void InitialiseVolumeMeasurement();
unsigned long GetPitchMeasurement();
unsigned long GetVolumeMeasurement();
unsigned long GetQMeasurement();
const float HZ_ADDVAL_FACTOR = 2.09785;
const float MIDDLE_C = 261.6;
void playNote(float hz, uint16_t milliseconds, uint8_t volume);
uint16_t log2U16 (uint16_t lin_input);
void hzToAddVal(float hz);
void playStartupSound();
void playCalibratingCountdownSound();
void playModeSettingSound();
void delay_NOP(unsigned long time);
void midi_setup();
void midi_msg_send(uint8_t channel, uint8_t midi_cmd1, uint8_t midi_cmd2, uint8_t midi_value);
void midi_application ();
void calculate_note_bend ();
void init_parameters ();
void set_parameters ();
};
#endif // _APPLICATION_H

@ -1,4 +1,4 @@
## Open Theremin V3 with MIDI interface control software V2.8 for Arduino UNO
## Open Theremin V3 with MIDI interface control software V2.9 for Arduino UNO
(For Open Theremin V4 with MIDI, follow this link: https://github.com/MrDham/OpenTheremin_V4_with_MIDI)
@ -7,7 +7,7 @@
Based on Arduino UNO Software for the Open.Theremin version 3.0 Copyright (C) 2010-2016 by Urs Gaudenz
https://github.com/GaudiLabs/OpenTheremin_V3
This Open Theremin V3 with MIDI version V2.6 also takes into account
This Open Theremin V3 with MIDI, since version V2.6, also takes into account
Changes added in Open.Theremin version 3.1 (all by @Theremingenieur):
Fix a wavetable addressing issue (found by @miguelfreitas)
@ -65,7 +65,7 @@ The MIDI open theremin generates NOTE ON/OFF messages and Continuous Controler
MIDI CC:
It is possible to affect independant MIDI CCs to the PITCH ANTENNA (ROD) and to the VOLUME ANTENNA (LOOP).
It is possible to assign independant MIDI CCs to the PITCH ANTENNA (ROD) and to the VOLUME ANTENNA (LOOP).
NOTE ON/OFF:
@ -165,7 +165,7 @@ Changing this to your taste may require some test and trial.
"#define VELOCITY_SENS 9" -> How easy it is to reach highest velocity (127). Something betwen 5 and 12.
"#define PLAYER_ACCURACY 0.2" -> Pitch accuracy of player. Tolerance on note center for changing notes when playing legato. From 0 (very accurate players) to 0.5 (may generate note toggling).
"#define PLAYER_ACCURACY 819" -> Pitch accuracy of player. Tolerance on note center for changing notes when playing legato. From 0 (very accurate players) to 2048 (may generate note toggling).
### NEED SUPPORT ?
Please log bugs, requests and questions at https://github.com/MrDham/OpenTheremin_V3_with_MIDI/issues

Loading…
Cancel
Save