giuliomoro
I manage to read all the Rotary switch and pot with 3 mux (4051). But I'm getting more and more lost in my code. I try to make a 5 independant input with 8 output to spatialise the sound of each input independently. I try to use the circulare-panning example, but know I'm lost. With the rotary switch, I choose a function for the input (clockwise, counterClockwise, random, all output, +++). With the first potentiometer, I try to control the speed of panning.
I have a lot of "crack" and "pop", probably to much volume when everything come together on the output. Don't know where to start... to clean, organise. Thanks for your help.
#include <Bela.h>
#include <cmath>
#include <random>
#include <libraries/Oscillator/Oscillator.h>
Oscillator lfos[5]; // Un LFO pour chaque entrée
float gLfoFreqRange[2] = {0.01, 1}; // LFO frequency range
unsigned int gCurrentChannel[5] = {0, 0, 0, 0, 0}; // Channel actif pour chaque entrée
float gPrevPanning[5] = {0.0, 0.0, 0.0, 0.0, 0.0}; // Valeur de panning précédente pour chaque entrée
int gChannelFunction[5] = {0, 0, 0, 0, 0}; // Choix de la fonction pour chaque entrée (0 = horaire, 1 = antihoraire, 2 = aléatoire, 3 = all)
unsigned int gChannelUpdateCounter[5] = {0, 0, 0, 0, 0};
int gNextChannelUpdateCounter[5] = {0, 0, 0, 0, 0};
int gRandomUpdateInterval = 1000; //stockage de la valeur vitesse random
const int s0Pin = 0;
const int s1Pin = 1;
const int s2Pin = 2;
const int enablePin = 3;
const int analogInPins[] = {0, 1, 2};
const int lorlinThresholds[] = {122, 367, 609, 854, 1000}; // Updated thresholds for Lorlin positions
static unsigned int frameCounter = 0;
// Paramètres du compresseur
float threshold = 0.5f; // Seuil de compression (entre 0 et 1)
float ratio = 1.0f; // Ratio de compression (supérieur à 1)
std::random_device rd; // générateur de nombres aléatoires
std::mt19937 rng(rd()); // initialisation de l'aléatoire
void selectChannel(BelaContext *context, int channel)
{
digitalWrite(context, 0, enablePin, LOW);
digitalWrite(context, 0, s0Pin, (channel & 0b001) ? HIGH : LOW);
digitalWrite(context, 0, s1Pin, (channel & 0b010) ? HIGH : LOW);
digitalWrite(context, 0, s2Pin, (channel & 0b100) ? HIGH : LOW);
}
int getLorlinPosition(int analogValue)
{
for (int i = 0; i < sizeof(lorlinThresholds) / sizeof(lorlinThresholds[0]); ++i)
{
if (analogValue < lorlinThresholds[i])
{
return i;
}
}
return sizeof(lorlinThresholds) / sizeof(lorlinThresholds[0]);
}
int getNextChannelClockwise(int channel, int numChannels)
{
int nextChannel = channel;
// Increment
nextChannel++;
// Wrap
if (nextChannel >= numChannels)
nextChannel = 0;
return nextChannel;
}
int getNextChannelCounterwise(int channel, int numChannels)
{
int nextChannel = channel;
// Decrement
nextChannel--;
// Wrap
if (nextChannel < 0)
nextChannel = numChannels - 1;
return nextChannel;
}
int getNextChannelRandom(int channel, int numChannels)
{
int nextChannel = channel;
std::uniform_int_distribution<int> dist(0, numChannels - 1);
while (nextChannel == channel) // S'assurer que le canal suivant est différent du canal actuel
{
nextChannel = dist(rng); // Choisissez un canal aléatoire entre 0 et numChannels-1
}
return nextChannel;
}
int getNextChannelAllOutputs(int channel, int numChannels)
{
return channel; // retourne simplement le canal d'entrée, car le son doit être diffusé sur toutes les sorties
}
float crossfade(float value, float fadeIn, float fadeOut)
{
return value * fadeIn * fadeOut;
}
bool setup(BelaContext *context, void *userData)
{
for (int i = 0; i < 5; ++i)
{
lfos[i].setup(context->audioSampleRate);
lfos[i].setFrequency((i + 1) * 0.25);
}
pinMode(context, 0, enablePin, OUTPUT);
digitalWrite(context, 0, enablePin, HIGH);
pinMode(context, 0, s0Pin, OUTPUT);
pinMode(context, 0, s1Pin, OUTPUT);
pinMode(context, 0, s2Pin, OUTPUT);
return true;
}
void render(BelaContext *context, void *userData)
{
for (unsigned int i = 0; i < 5; i++)
{
gNextChannelUpdateCounter[i]++;
// float lfoPeriod = context->audioSampleRate / lfos[i].getFrequency();
if (gChannelFunction[i] == 0) // horaire
{
if (gChannelUpdateCounter[i] % gRandomUpdateInterval == 0) {
gCurrentChannel[i] = getNextChannelClockwise(gCurrentChannel[i], context->audioOutChannels);
gChannelUpdateCounter[i] = 0;
}
}
else if (gChannelFunction[i] == 1) // antihoraire
{
if (gChannelUpdateCounter[i] % gRandomUpdateInterval == 0) {
gCurrentChannel[i] = getNextChannelCounterwise(gCurrentChannel[i], context->audioOutChannels);
gChannelUpdateCounter[i] = 0;
}
}
}
static int channel = 0;
if (context->multiplexerStartingChannel == 0)
{
selectChannel(context, channel);
for (int mux = 0; mux < 3; ++mux)
{
int analogValue = analogRead(context, 0, analogInPins[mux]) * 1023;
if (mux == 0)
{
int lorlinPosition = getLorlinPosition(analogValue);
gChannelFunction[channel] = lorlinPosition;
}
else if (mux == 1)
{
float normalizedAnalogValue = (float)analogValue / 1023.0;
float lfoFreq = normalizedAnalogValue * (gLfoFreqRange[1] - gLfoFreqRange[0]) + gLfoFreqRange[0];
lfos[channel].setFrequency(lfoFreq);
if (frameCounter % 1000 == 0) {
rt_printf("Analog value: %d, Normalized value: %f, LFO frequency: %f\n", analogValue, normalizedAnalogValue, lfoFreq);
}
if (gChannelFunction[channel] == 2) // Lorsque la fonction aléatoire est sélectionnée
{
gRandomUpdateInterval = map(analogValue, 0, 1023, 500, 5000); // Ajustez les valeurs minimale et maximale selon vos besoins
}
}
}
rt_printf("\n");
channel = (channel + 1) % 5;
}
// Paramètres du compresseur
float threshold = 0.9f; // Seuil de compression (entre 0 et 1)
float ratio = 1.0f; // Ratio de compression (supérieur à 1)
float lfoSmoothFactor = 0.995f; // Ajustez cette valeur pour un lissage plus ou moins important (entre 0 et 1, proche de 1 pour un lissage plus fort)
for (unsigned int n = 0; n < context->audioFrames; n++)
{
float in[5];
for (unsigned int i = 0; i < 5; i++)
{
in[i] = audioRead(context, n, i);
}
for (unsigned int ch = 0; ch < context->audioOutChannels; ch++)
{
float out[8] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
for (unsigned int i = 0; i < 5; i++)
{
float lfoValue = lfos[i].process();
gPrevPanning[i] = gPrevPanning[i] * lfoSmoothFactor + lfoValue * (1.0f - lfoSmoothFactor);
float panning = gPrevPanning[i] * 0.5f + 0.5f; // Valeur entre 0 et 1
int nextChannel = 0;
switch (gChannelFunction[i])
{
case 0: // horaire
nextChannel = getNextChannelClockwise(gCurrentChannel[i], context->audioOutChannels);
if (frameCounter % 1000 == 0) {
//rt_printf("Next Channel : %d | ", nextChannel); // Affiche le canal suivant aléatoire
// rt_printf("\n");
}
break;
case 1: // antihoraire
nextChannel = getNextChannelCounterwise(gCurrentChannel[i], context->audioOutChannels);
break;
case 2: // aléatoire
if (frameCounter % gRandomUpdateInterval == 0) {
nextChannel = getNextChannelRandom(gCurrentChannel[i], context->audioOutChannels);
} else {
nextChannel = gCurrentChannel[i];
}
break;
case 3: // all
nextChannel = getNextChannelAllOutputs(gCurrentChannel[i], context->audioOutChannels);
break;
}
// FADE IN FADE OUT
float fadeIn = (gChannelFunction[i] == 3) ? 1.0f : panning;
float fadeOut = (gChannelFunction[i] == 3) ? 1.0f : 1.0f - panning;
if (ch == gCurrentChannel[i])
{
out[ch] += crossfade(in[i], fadeIn, fadeOut);
}
else if (ch == nextChannel)
{
out[ch] += crossfade(in[i], fadeIn, fadeOut);
}
// sorties
float chPanning = 0.0;
gCurrentChannel[i] = nextChannel;
if (gChannelFunction[i] == 3) // all
{
chPanning = 1.f - panning;
for (int j = 0; j < context->audioOutChannels; ++j)
{
out[j] += in[i] * chPanning;
}
out[ch] *= 0.5;
}
else
{
if (ch == gCurrentChannel[i])
{
chPanning = 1.f - panning;
}
else if (ch == nextChannel)
{
chPanning = panning;
}
else
{
chPanning = 0.0;
}
float signal = in[i] * chPanning;
// Appliquer la compression si le signal dépasse le seuil
if (fabs(signal) > threshold)
{
float gainReduction = (fabs(signal) - threshold) / ratio;
signal = (signal > 0 ? 1 : -1) * (fabs(signal) - gainReduction);
}
out[ch] += signal;
}
}
out[ch] *= 0.1; // Réduire le niveau du signal de 20%
audioWrite(context, n, ch, out[ch]);
}
}
frameCounter++;
}
void cleanup(BelaContext *context, void *userData)
{
}