The position on the Ring sensor is used to control a Shepard-Risset infinite glissando effect. This auditory illusion involves a bank of sinetones which are tuned an octave apart whose pitch changes in unison. The pitch changing across all of the sinetones at the same time creates an auditory illusion of a tone that is forever increasing or decreasing in pitch.
In this example we have mapped position around the ring to pitch with one full rotation around the Ring being mapped to an octave. To hear the auditory illusion to its full effect try moving your finger around the Trill Ring sensor at a steady pace.
#include <libraries/Scope/Scope.h>
#include <libraries/Gui/Gui.h>
#include <libraries/Trill/Trill.h>
#include <libraries/Oscillator/Oscillator.h>
#include <cmath>
#include <vector>
#define NUM_TOUCH 5 // Number of touches on Trill sensor
const unsigned int kNumOscillators = 8;
const float kFrequencyRatio = 2.0;
const float kLowestBaseFrequency = 30.0;
const unsigned int kSpectralWindowSize = 1024;
const float kAmplitude = 0.1;
const float kMaxFrequencyRatio = log(powf(kFrequencyRatio, kNumOscillators)) / log(2.0);
const unsigned int kUpdateInterval = 64;
unsigned int gUpdateCount = 0;
const float kGuiTimePeriod = 1.0 / 25.0;
unsigned int gGuiCount = 0;
std::vector<Oscillator> gOscillators;
std::vector<float> gLogFrequencies;
std::vector<float> gAmplitudes;
std::vector<float> gSpectralWindow;
float gTouchLocationCycle = 0;
float gTouchSizeCycle = 0;
float gTouchLocation[NUM_TOUCH] = { 0.0, 0.0, 0.0, 0.0, 0.0 };
float gTouchSize[NUM_TOUCH] = { 0.0, 0.0, 0.0, 0.0, 0.0 };
unsigned int gNumActiveTouches = 0;
unsigned int gTaskSleepTime = 12000;
float gTimePeriod = 0.015;
void loop(void*)
{
int wraps = 0;
float pastRead = 0;
{
for(unsigned int i = 0; i < gNumActiveTouches; i++) {
}
for(unsigned int i = gNumActiveTouches; i < NUM_TOUCH; i++) {
gTouchLocation[i] = 0.0;
gTouchSize[i] = 0.0;
}
{
if(pastRead > 0.92 && newRead < 0.08) {
wraps++;
} else if(newRead > 0.92 && pastRead < 0.08) {
wraps--;
}
if(wraps < 0)
wraps += 8;
wraps %= 8;
gTouchLocationCycle = newRead + wraps;
pastRead = newRead;
} else {
}
usleep(gTaskSleepTime);
}
}
{
fprintf(stderr, "Unable to initialise Trill Ring\n");
return false;
}
for(unsigned int i = 0; i < kNumOscillators; i++)
{
}
gLogFrequencies.resize(kNumOscillators);
for(unsigned int i = 0; i < kNumOscillators; i++)
{
gLogFrequencies[i] = (float)i / (float)kNumOscillators;
}
gAmplitudes.resize(kNumOscillators);
for(unsigned int i = 0; i < kNumOscillators; i++)
{
gAmplitudes[i] = 0;
}
gSpectralWindow.resize(kSpectralWindowSize);
for(unsigned int n = 0; n < kSpectralWindowSize; n++)
{
gSpectralWindow[n] = 0.5f * (1.0f - cosf(2.0 * M_PI * n / (float)(kSpectralWindowSize - 1)));
}
return true;
}
{
for(unsigned int i = 0; i < kNumOscillators; i++)
{
gLogFrequencies[i] = fmodf((float)i / (float)kNumOscillators + gTouchLocationCycle/kNumOscillators, 1);
gAmplitudes[i] = gSpectralWindow[(int)(gLogFrequencies[i] * kSpectralWindowSize)];
}
{
if(gUpdateCount >= kUpdateInterval)
{
gUpdateCount = 0;
for(unsigned int i = 0; i < kNumOscillators; i++)
{
float frequency = kLowestBaseFrequency * powf(2.0, gLogFrequencies[i] * kMaxFrequencyRatio);
gOscillators[i].setFrequency(frequency);
}
}
++gUpdateCount;
float out = 0;
for(unsigned int i = 0; i < kNumOscillators; i++)
{
out += gOscillators[i].process() * gAmplitudes[i] * kAmplitude;
}
{
}
{
gGuiCount = 0;
}
++gGuiCount;
}
}
{
}