Skip to content

Commit

Permalink
Merge pull request GaudiLabs#3 from Theremingenieur/4.0.1
Browse files Browse the repository at this point in the history
4.0.1
  • Loading branch information
Theremingenieur authored Jan 7, 2022
2 parents 52c9d44 + 8877d4e commit 4476d24
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 20 deletions.
6 changes: 4 additions & 2 deletions Software/Open_Theremin_V4/Open_Theremin_V4.ino
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Open.Theremin control software for Arduino UNO
* Version 3.1
* Version 4.0.1
* Copyright (C) 2010-2020 by Urs Gaudenz
*
* Open.Theremin control software is free software: you can redistribute it and/or
Expand Down Expand Up @@ -31,7 +31,9 @@ ENABLE_SERIAL - if non-0, the build will include code to write the detected
pitch to the serial connection every 100 milliseconds. Set serial
receive baud to 115200
ENABLE_CV - if non-0, emit cv output on pin 6 (EXPERIMENTAL!)
CV_LOG - if non-0, the pitch CV output will follow the Moog/Roland standard
of logarithmic 1V/Octave, else it will follow the linear Korg/Yamaha
standard with 819Hz/V
Structure of the code
=====================
Expand Down
58 changes: 43 additions & 15 deletions Software/Open_Theremin_V4/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ AppMode Application::nextMode()
void Application::loop()
{
int32_t pitch_v = 0, pitch_l = 0; // Last value of pitch (for filtering)
int32_t vol_v = 0, vol_l = 0; // Last value of volume (for filtering)
int32_t vol_v = 0, vol_l = 0; // Last value of volume (for filtering and for tracking)

uint16_t volumePotValue = 0;
uint16_t pitchPotValue = 0;
Expand All @@ -163,7 +163,7 @@ void Application::loop()
uint8_t registerValue = 2;
uint16_t tmpVolume;
int16_t tmpPitch;
uint8_t tmpOct;
uint16_t tmpOct;
uint16_t tmpLog;

mloop: // Main loop avoiding the GCC "optimization"
Expand Down Expand Up @@ -256,7 +256,7 @@ void Application::loop()

if (pitchValueAvailable)
{ // If capture event

pitch_p = pitch;
pitch_v = pitch; // Averaging pitch values
pitch_v = pitch_l + ((pitch_v - pitch_l) >> 2);
pitch_l = pitch_v;
Expand All @@ -273,19 +273,25 @@ void Application::loop()
tmpPitch = min(tmpPitch, 16383); // Unaudible upper limit just to prevent DAC overflow
tmpPitch = max(tmpPitch, 0); // Silence behing zero beat
setWavetableSampleAdvance(tmpPitch >> registerValue);
if (tmpPitch != pitch_p)
{ // output new pitch CV value only if pitch value changed (saves runtime resources)
pitch_p = tmpPitch;
#if CV_LOG
tmpOct = 0;
while (tmpPitch > 1023) {
tmpOct += 1;
tmpPitch >>= 1;
}
tmpPitch = max(tmpPitch, 512) - 512;
tmpLog = ((uint16_t)tmpPitch >> 3) * 819 >> 6;
pitchCV = max(tmpOct * 820 + tmpLog - 48, 0); // ~1V/Oct for Moog & Roland
tmpOct = 0;
while (tmpPitch > 1023) {
tmpOct += 819;
tmpPitch >>= 1;
}
tmpPitch -= 512;
tmpPitch = max(tmpPitch, 0);
tmpLog = (((uint32_t)tmpPitch * 819) >> 9);
pitchCV = (tmpOct + tmpLog) - 48;
pitchCV = max(pitchCV, 0); // 1V/Oct for Moog & Roland
#else
pitchCV = tmpPitch >> 2; // ~800Hz/V for Korg & Yamaha
pitchCV = tmpPitch >> 2; // 819Hz/V for Korg & Yamaha
#endif
pitchCVAvailable = true;
pitchCVAvailable = true;
}
break;
};

Expand All @@ -294,8 +300,9 @@ void Application::loop()
pitchValueAvailable = false;
}

if (volumeValueAvailable)
{
if (volumeValueAvailable && (vol != vol_p))
{ // If capture event AND volume value changed (saves runtime resources)
vol_p = vol;
vol = max(vol, 5000);

vol_v = vol; // Averaging volume values
Expand Down Expand Up @@ -324,6 +331,27 @@ void Application::loop()
// Give vScaledVolume a pseudo-exponential characteristic:
vScaledVolume = tmpVolume * (tmpVolume + 2);

tmpVolume = tmpVolume >> 1;

if (!gate_p && (tmpVolume >= GATE_ON))
{
gate_p = true;
// pull the gate up to sense, first (to prevent short-circuiting the IO pin:
GATE_PULLUP;
if (GATE_SENSE)
{ // if it goes up, drive the gate full high:
GATE_DRIVE_HIGH;
}
}
else if (gate_p && (tmpVolume <= GATE_OFF))
{
gate_p = false;
// drive the gate low:
GATE_DRIVE_LOW;
}



volumeValueAvailable = false;
}

Expand Down
4 changes: 3 additions & 1 deletion Software/Open_Theremin_V4/application.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ class Application {
static const int16_t VOLUME_POT = 1;
static const int16_t WAVE_SELECT_POT = 7;
static const int16_t REGISTER_SELECT_POT = 6;

int16_t pitch_p = -1;
int32_t vol_p = -1;
bool gate_p = false;


#if SERIAL_ENABLED
Expand Down
5 changes: 5 additions & 0 deletions Software/Open_Theremin_V4/build.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,10 @@
// Set to build with logarithmic 1V/oct pitch control voltage output
#define CV_LOG 1

// Set the trigger levels for the Gate signal (0 to 127 in preparation for later midi extensions)
#define GATE_ON 20 // That's the level which will drive the Gate high when volume increases from lower
#define GATE_OFF 16 // That's the level which will drive the Gate low when volume decreases from higher
// Making both values equal risk the gate signal to bounce, leave at least 4 (hysteresis) between both.
// Set both to 128 to disable the Gate Signal.

#endif // _BUILD_H
6 changes: 6 additions & 0 deletions Software/Open_Theremin_V4/hw.h
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

#ifndef _HW_H
#define _HW_H

Expand All @@ -14,4 +15,9 @@
#define HW_LED1_TOGGLE (PORTC = PORTC ^ (1<<PORTC4))
#define HW_LED2_TOGGLE (PORTC = PORTC ^ (1<<PORTC5))

#define GATE_PULLUP (DDRC &= ~(1<<PORTC2)); (PORTC |= (1<<PORTC2))
#define GATE_SENSE (PINC & (1<<PORTC2))
#define GATE_DRIVE_HIGH (DDRC |= (1<<PORTC2))
#define GATE_DRIVE_LOW (PORTC &= ~(1<<PORTC2)); (DDRC |= (1<<PORTC2))

#endif // _HW_H
2 changes: 1 addition & 1 deletion Software/Open_Theremin_V4/ihandlers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ volatile uint16_t vol_counter = 0;
volatile uint16_t vol_counter_i = 0; // Volume counter
volatile uint16_t vol_counter_l; // Last value of volume counter

volatile uint16_t pitchCV; // Pitch CV value
volatile int16_t pitchCV; // Pitch CV value
volatile uint16_t volCV; // Volume CV value
volatile bool volumeCVAvailable; // Volume CV flag
volatile bool pitchCVAvailable; // Pitch CV flag
Expand Down
2 changes: 1 addition & 1 deletion Software/Open_Theremin_V4/ihandlers.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
extern volatile uint16_t pitch; // Pitch value
extern volatile uint16_t vol; // Volume value
extern volatile uint16_t vScaledVolume; // Volume byte
extern volatile uint16_t pitchCV; // Pitch CV value
extern volatile int16_t pitchCV; // Pitch CV value
extern volatile uint16_t volCV; // Volume CV value

extern volatile uint16_t pitch_counter; // Pitch counter
Expand Down

0 comments on commit 4476d24

Please sign in to comment.