Sintetizzatore virtuale MOZZI/Fishino by Gianroberto Negri

A questo punto con l’istruzione riportata di seguito creeremo un oscillatore sinusoidale:

Oscil <2048, AUDIO_RATE> aSin(SIN2048_DATA);

Un valore che importante è il CONTROL_RATE. Esso ha un valore predefinito di 64, ma si può cambiare se si desidera controllare gli aggiornamenti più spesso. Anche in questo caso deve essere un numero potenza di due per permettere a Mozzi di ottimizzare i calcoli e di conseguenza la velocità di esecuzione.

#define CONTROL_RATE 128

Il valore và inserito come parametro in startMozzi() che si trova in  setup ():

startMozzi(CONTROL_RATE);

Esso imposta un timer per chiamare updateControl () alla frequenza impostata.
La frequenza dell’oscillatore appena creato può essere impostata in numerosi modi , in questo caso la imposteremo a 440Hz.:

aSin.setFreq(440);

Ora il setup () diventa:

void setup(){
startMozzi(CONTROL_RATE);
aSin.setFreq(440);
}

Le prossime funzioni necessarie da inserire sono updateControl () e updateAudio ().
In questo esempio, la frequenza è già stata impostata e l’oscillatore ha solo bisogno di essere eseguito in updateAudio () , utilizzando il aSin.next().

void updateControl(){
  // no controls being changed
}
int updateAudio(){
  return aSin.next();
}

Come ultima funzione inseriremo audioHook () in loop () .

void loop(){
  audioHook();
}

Mediante questa funzione la generazione del suono viene effettivamente sintetizzata, in base ai parametri impostati in precedenza. Il buffer di uscita che viene costantemente riempito e svuotato alla frequenza audio di Mozzi. Per questo motivo, di solito è meglio di evitare di mettere qualsiasi altro codice in loop () . E ‘importante per la progettazione di uno programma efficiente inserire i calcoli lenti in updateControl () e setup () . Mentre è meglio mantenere updateAudio () con meno codice possibile.

Ecco l’intero Programma:

#include <MozziGuts.h>
#include <Oscil.h>
#include <tables/sin2048_int8.h>

#define CONTROL_RATE 128
Oscil <2048, AUDIO_RATE> aSin(SIN2048_DATA);

void setup(){
  aSin.setFreq(440);
  startMozzi(CONTROL_RATE);
}

void updateControl(){
}

int updateAudio(){
  return aSin.next();
}

void loop(){
  audioHook();
}

Aggiunta di un segnale: controllo vibrato

Il Vibrato può essere aggiunto al programma cambiando periodicamente la frequenza dell’onda audio con un oscillatore a bassa frequenza.  Il nuovo controllo utilizzerà i medesimi parametri prima impostati. Per convenzione utilizzeremo come lettera iniziale del controllo ‘k’.

Oscil <2048, CONTROL_RATE> kVib(SIN2048_DATA);

Questa volta la frequenza può essere impostata con un valore in virgola mobile:

kVib.setFreq(6.5f);

Ora l’oscillatore  ddel vibrato può modulare la frequenza dell’oscillatore audio mediante KVib.next ()  inserita in updateControl ().

void updateControl(){
  float vibrato = depth * kVib.next();
  aSin.setFreq(centre_freq+vibrato);
}

Ecco ul programma del vibrato:

#include <MozziGuts.h>
#include <Oscil.h>
#include <tables/sin2048_int8.h>

#define CONTROL_RATE 128
Oscil <2048, AUDIO_RATE> aSin(SIN2048_DATA);
Oscil <2048, CONTROL_RATE> kVib(SIN2048_DATA);

float centre_freq = 440.0;
float depth = 0.25;

void setup(){
  kVib.setFreq(6.5f);
  startMozzi(CONTROL_RATE);
}

void updateControl(){
  float vibrato = depth * kVib.next();
  aSin.setFreq(centre_freq+vibrato);
}

int updateAudio(){
  return aSin.next();
}

void loop(){
  audioHook();
}

Il nostro progetto:

A questo punto abbiamo le basi per realizzare qualcosa di nostro da far vedere con orgoglio ad amici e parenti dicendo ‘Questo l’ho fatto io’. Una premessa hardware riguardo Fishino e Mozzi… l’uscita audio si trova sul pin 9 . Per cui se si vuole collegare una cuffia per ascoltare il suono generato la stessa và collegata al pin 9 come più ad a gnd come massa. Vediamo il codice  completo del programma che gira sotto Fishino che poi andremo ad analizzare passo, passo in particolare per la parte che riguarda il protocollo.

#include <MozziGuts.h>
#include <Oscil.h> // oscillator 
#include <tables/cos2048_int8.h> // table suoni x Oscils
#include <Smooth.h>
#include <AutoMap.h> // maps input imprevisti riguardo il range

#define CONTROL_RATE 256

const byte numChars = 32;
char receivedChars[numChars];
String receivedCharsS;
boolean newData = false;

/**********************************************
 * definizzione variabili dei comandi 
 * di ingresso dalla seriale
 */
int freqVal;
int knob2;
int knob_value;
int LDR1_value;
int LDR2_value;

// minima e massima frequnza della portante
const int MIN_CARRIER_FREQ = 22;
const int MAX_CARRIER_FREQ = 440;

const int MIN = 1;
const int MAX = 10;

const int MIN_2 = 1;
const int MAX_2 = 15;

// Intensità desiderata max e min, per AutoMap, si noti che a causa della dinamica inversa sono invertiti
const int MIN_INTENSITY = 700;
const int MAX_INTENSITY = 10;

// velocità minima e massima per AutoMap, si noti che a causa della dinamica inversa sono invertiti
const int MIN_MOD_SPEED = 10000;
const int MAX_MOD_SPEED = 1;

AutoMap kMapCarrierFreq(0, 1023, MIN_CARRIER_FREQ, MAX_CARRIER_FREQ);
AutoMap kMapIntensity(0, 1023, MIN_INTENSITY, MAX_INTENSITY);
AutoMap kMapModSpeed(0, 1023, MIN_MOD_SPEED, MAX_MOD_SPEED);
AutoMap mapThis(0, 1023, MIN, MAX);
AutoMap mapThisToo(0, 1023, MIN_2, MAX_2);

Oscil<COS2048_NUM_CELLS, AUDIO_RATE> aCarrier(COS2048_DATA);
Oscil<COS2048_NUM_CELLS, AUDIO_RATE> aModulator(COS2048_DATA);
Oscil<COS2048_NUM_CELLS, CONTROL_RATE> kIntensityMod(COS2048_DATA);

int mod_ratio = 5; // limpidezza (armoniche)
long fm_intensity; // variabile x intensità da updateControl a updateAudio

// per fulizia della gnerazione del suono
float smoothness = 0.95f;
Smooth <long> aSmoothIntensity(smoothness);


void setup() {
  Serial.begin(115200); // set up  Seriale
  startMozzi(CONTROL_RATE);
}

void updateControl() {
  recvWithStartEndMarkers();
  showNewData();
  /***********************************
     ricezione comandi da vb.net
   ***********************************/
  int Test = receivedCharsS.indexOf("LDR3");
  if (Test >= 0) { 
    Serial.print("CMD 1 "+receivedCharsS+"\n");
    int TestV = receivedCharsS.indexOf(":");
    if (TestV >= 0) {
      Serial.print("CMD 2 "+receivedCharsS+"\n");
      String Valore = receivedCharsS.substring(TestV + 1, receivedCharsS.length());
      int Val = Valore.toInt();
      freqVal = Val;
      Serial.print("CMD 3 "+receivedCharsS+"\n");
    }
  }

int Test2 = receivedCharsS.indexOf("LDR4");
  if (Test2 >= 0) { 
    Serial.print("CMD 1 "+receivedCharsS+"\n");
    int TestV = receivedCharsS.indexOf(":");
    if (TestV >= 0) {
      Serial.print("CMD 2 "+receivedCharsS+"\n");
      String Valore = receivedCharsS.substring(TestV + 1, receivedCharsS.length());
      int Val = Valore.toInt();
      knob2 = Val;
      Serial.print("CMD 3 "+receivedCharsS+"\n");
    }
  }

int  Test3 = receivedCharsS.indexOf("KNOB");
  if (Test3 >= 0) {
    Serial.print("CMD 1 "+receivedCharsS+"\n");
    int TestV = receivedCharsS.indexOf(":");
    if (TestV >= 0) {
      Serial.print("CMD 2 "+receivedCharsS+"\n");
      String Valore = receivedCharsS.substring(TestV + 1, receivedCharsS.length());
      int Val = Valore.toInt();
      knob_value = Val;
      Serial.print("CMD 3 "+receivedCharsS+"\n");
    }
  }

  int FRQ = mapThis(freqVal);
  int knob2Val = mapThis(knob2);
  // map la varabile knob_value sulla portante della frequenza
  //-------------------------------------------------------
  int carrier_freq = kMapCarrierFreq(knob_value);
  //Calcola il rapporto della frequenza di modulazione
  //-------------------------------------------------
  int mod_freq = carrier_freq * mod_ratio * FRQ;
  // setta la frequenza dell'oscillatore FM
  //------------------------------------------------
  aCarrier.setFreq(carrier_freq);
  aModulator.setFreq(mod_freq);

int  Test4 = receivedCharsS.indexOf("LDR1");
  if (Test4 >= 0) { 
    Serial.print("CMD 1 "+receivedCharsS+"\n");
    int TestV = receivedCharsS.indexOf(":");
    if (TestV >= 0) {
      Serial.print("CMD 2 "+receivedCharsS+"\n");
      String Valore = receivedCharsS.substring(TestV + 1, receivedCharsS.length());
      int Val = Valore.toInt();
      LDR1_value = Val;
      Serial.print("CMD 3 "+receivedCharsS+"\n");
    }
  }


  int LDR1_calibrated = kMapIntensity(LDR1_value);
   // calculate the fm_intensity
  fm_intensity = ((long)LDR1_calibrated * knob2Val * (kIntensityMod.next() + 128)) >> 8; //lo shift >> 8 equivale ad una moltiplicazione a 8 bit

 int Test5 = receivedCharsS.indexOf("LDR2");
  if (Test5 >= 0) {
    Serial.print("CMD 1 "+receivedCharsS+"\n");
    int TestV = receivedCharsS.indexOf(":");
    if (TestV >= 0) {
      Serial.print("CMD 2 "+receivedCharsS+"\n");
      String Valore = receivedCharsS.substring(TestV + 1, receivedCharsS.length());
      int Val = Valore.toInt();
      LDR2_value = Val;
      Serial.print("CMD 3 "+receivedCharsS+"\n");
    }
  }
  // usa una variabile float per le basse frequenze
  float mod_speed = (float)kMapModSpeed(LDR2_value) / 1000;
  kIntensityMod.setFreq(mod_speed);

}

int updateAudio() {
  long modulation = aSmoothIntensity.next(fm_intensity) * aModulator.next();
  return aCarrier.phMod(modulation);
}

void loop() {
  audioHook();
}

void recvWithStartEndMarkers() {
  static boolean recvInProgress = false;
  static byte ndx = 0;
  char startMarker = '<';
  char endMarker = '>';
  char rc;
  receivedCharsS = "";

  // if (Serial.available() > 0) {
  while (Serial.available() > 0 && newData == false) {
    rc = Serial.read();

    if (recvInProgress == true) {
      if (rc != endMarker) {
        receivedChars[ndx] = rc;
        receivedCharsS += rc;
        ndx++;
        if (ndx >= numChars) {
          ndx = numChars - 1;
        }
      }
      else {
        receivedChars[ndx] = '\0'; // terminate the string
        recvInProgress = false;
        ndx = 0;
        newData = true;
      }
    }

    else if (rc == startMarker) {
      recvInProgress = true;
    }
  }
}

void showNewData() {
  if (newData == true) {
    Serial.print("This just in ... ");
    Serial.print(receivedCharsS+"-");
    Serial.println(receivedChars);
    newData = false;
  }
}

3 Commenti

  1. interessante applicazione tra visualstudio 2010 e fishino. interessante la spiegazione della libreria mozzi resa semplice per tutti.
  2. splendido progetto, proverò a repricarlo. Se uso un fishino Mega invece di un fishino uno devo modificare qualcosa o prendere degli accorgimenti? Grazie

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.

Main Menu