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 
 
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;
        {
 
                
                touchSensor.readI2C();
                gNumActiveTouches = touchSensor.getNumTouches();
                for(unsigned int i = 0; i < gNumActiveTouches; i++) {
                        gTouchLocation[i] = touchSensor.touchLocation(i);
                        gTouchSize[i] = touchSensor.touchSize(i);
                }
                
                for(unsigned int i = gNumActiveTouches; i < NUM_TOUCH; i++) {
                        gTouchLocation[i] = 0.0;
                        gTouchSize[i] = 0.0;
                }
 
                if(touchSensor.getNumTouches())
                {
                        float newRead = touchSensor.compoundTouchLocation();
                        
                        
                        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;
                        gTouchSizeCycle = touchSensor.compoundTouchSize();
                        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)));
        }
 
        
 
        
 
        
        gGui.setBuffer('f', 3); 
 
        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;
                }
 
                
                {
                }
 
                
                gScope.log(out);
 
                
                {
                        gGuiCount = 0;
 
                        
                        gGui.sendBuffer(0, 1);
                        gGui.sendBuffer(1, gTouchLocation);
                        gGui.sendBuffer(2, gTouchSize);
                        
                        gGui.sendBuffer(3, (int)kNumOscillators);
                        gGui.sendBuffer(4, gTouchLocationCycle + 1000.0);
                }
                ++gGuiCount;
        }
}
 
{
}
Definition Oscillator.h:3
An oscilloscope which allows data to be visualised in a browser in real time.
Definition Scope.h:23
A class to use the Trill family of capacitive sensors. http://bela.io/trill.
Definition Trill.h:14
void printDetails()
Definition Trill.cpp:492
@ RING
Trill Ring
Definition Trill.h:37
AuxiliaryTask Bela_runAuxiliaryTask(void(*callback)(void *), int priority=0, void *arg=nullptr)
Create and start an AuxiliaryTask.
int Bela_stopRequested()
Check whether the program should stop.
static void audioWrite(BelaContext *context, int frame, int channel, float value)
Write an audio output, specifying the frame number (when to write) and the channel.
Definition Bela.h:1469
void render(BelaContext *context, void *userData)
User-defined callback function to process audio and sensor data.
Definition render.cpp:68
bool setup(BelaContext *context, void *userData)
User-defined initialisation function which runs before audio rendering begins.
Definition render.cpp:51
void cleanup(BelaContext *context, void *userData)
User-defined cleanup function which runs when the program finishes.
Definition render.cpp:96
Structure holding audio and sensor settings and pointers to I/O data buffers.
Definition Bela.h:231
const uint32_t audioOutChannels
The number of audio output channels.
Definition Bela.h:326
const uint32_t audioFrames
The number of audio frames per block.
Definition Bela.h:322
char projectName[MAX_PROJECTNAME_LENGTH]
Name of running project.
Definition Bela.h:417
const float audioSampleRate
The audio sample rate in Hz (currently always 44100.0).
Definition Bela.h:328