Realizzazione software
 

Il programma che implementa il modello di chitarra acustica in esame è stato sviluppato in linguaggio C++, a contorno delle routine del algoritmo è stata realizzata un interfaccia grafica in ambiente Microsoft Windowsâ , attraverso la quale è possibile interagire sul modello in tempo reale.
 
 

Oggetti in C++ per circuiti a tempo discreto

Il linguaggio C++ a differenza del AnsiC, consente con le "classi" la creazione di oggetti. Un oggetto in C++ può essere creato sia in fase di compilazione che durante l’esecuzione del programma, alla creazione di un oggetto segue la creazione di un’insieme di variabili private del oggetto, e normalmente invisibili dall’esterno, in aggiunta vengono associate delle funzioni (funzioni membro), che possono accedere ed elaborare le variabili private, ed essere accessibili dall’esterno se definite opportunamente.

Nella realizzazione di circuiti a tempo discreto, la programmazione ad oggetti può essere utilizzata vantaggiosamente. Ad esempio il programma che realizza una linea di ritardo è composto dalle celle di memoria che contengono i dati e da un algoritmo che gestisce i puntatori alla memoria, in un programma più generale, l’utilizzo di più elementi può portare a problemi di complessità e di scarsa leggibilità; ricorrendo all’uso di oggetti, ad esempio definendo la classe DelayLine (linea di ritardo), come composta da variabili private tra le quali il vettore dei dati e da una o più funzioni membro accessibile dall’esterno che realizzano l’algoritmo; durante l’esecuzione del programma ad ogni chiamata, la funzione elabora i dati propri del oggetto, nel caso della linea di ritardo, restituisce l’ultimo elemento della linea.

La scelta degli oggetti, oltre a semplificare la struttura del programma e la gestione degli elementi circuitali, permette la facile realizzazione di oggetti durante l’esecuzione del programma stesso.

Qui di seguito è riportato la dichiarazione della classe DelayLine estratta dal file d’intestazione zobj.h.
 
 

                class DelayLine
                             {
                                public:
                              DelayLine(int tap);

DelayLine() {
ttap=new int[100];
dimension=100;offset=0;
aux=0;
};
~DelayLine(){delete ttap;};
int Procsamp(int *punt);
int Procsamp(int *punt,int node);
int Fixnode(int node);
int Runnode(int node);
void Loadtap(int punt[]);
void Resettap();
int Gettap(int node);
private:
int offset,aux;
int *ttap;
int dimension;
};
All’interno del programma principale, la creazione di una di una DL va fatta con la dichiarazione DelayLine(num_rit), ad esempio
La funzione membro che realizza l’algoritmo è Procsamp(indirizzodato,[numnodo]), ed è definita nella routine zobj.cpp, come segue.

Fig.16

La funzione Procsamp restituisce un intero ed ha come argomento l’indirizzo della cella di memoria contenente il dato in ingresso alla DL, inoltre con l’argomento opzionale numnodo, è possibile scegliere da quale nodo prelevare l’uscita.
 

DelayLine::DelayLine(int tap)
            {
            ttap=new int[(tap+1)];
            dimension=(tap+1);offset=0;aux=0;
            }
            ...

int DelayLine::Procsamp(int *punt)
            {
            ttap[offset]=*punt;
            offset++;
            offset%=dimension;
            return(ttap[offset]);
            }
int DelayLine::Procsamp(int *punt,int node)
            {
            ttap[offset]=*punt;
            ffset++;offset%=dimension;
            aux=((node+offset)%dimension);
            return(ttap[aux]);
            }

L’oggetto StringModel

Il modello della corda di chitarra proposto è stato racchiuso nel oggetto StringModel. La definizione della classe StringModel è contenuta le file d’intestazione myobj.h, le relative funzioni membro sono contenute nel file myobj.cpp, i listati completi sono riportati in appendice.
Nel programma principale la dichiarazione StringModel cordax(note), crea un modello di corda identificato con cordax, il parametro note, stabilisce la nota più bassa che cordax è capace di sintetizzare.


Note
Nota
Frequenza(Hz)
0
A1
55
1
               A#1
58.27
2
B1
61.73
3
C2
65.40
12
A2
110

Dato che si vuole sintetizzare sei corde di una chitarra acustica, secondo la normale accordatura, nella definizione delle corde il parametro note deve valere.


Nota
Note
Frequenza(Hz)
E2 (Mi BASSO)
7
82.40
A2
12
110
D3
17
146.83
G3
22
195.99
B3
26
246.94
E4 (Mi Cantino)
31
329.62

Il modello di una singola corda realizzato da StringModel, può essere schematizzato in figura.
 



Fig.17


 






In figura oltre ai blocchi funzionali sono messe in evidenza le funzioni membro che permettono dall’esterno di agire sui parametri del modello.

  • La funzione Param(mp,gc,gain,cutoff,detune,fine_detune,mo) consente di fissare i parametri del modello, quali:
  •         mp ripartizione del segnale d’ingresso sulle due polarizzazioni.
  •         gc accoppiamento tra la polarizzazione orizzontale quella verticale. ,
  •         gain guadagno dei filtri appartenenti ai loop di corda.
  •         cutoff taglio dei filtri dei loop di corda.
  •         detune differenza intera tra le fondamentali prodotte dalle due polarizzazioni.
  •         fine_detune come detune solo con valori non interi compresi tra –1 e 1.
  •         mo ripartizione delle polarizzazioni sull’uscita.

  •  

     

    Le altre funzioni:

    Incoup(gm1, gm2, gm3, gm4, gm5, &gm1,& gm2,& gm3,& gm4,& gm5),consente l’accoppiamento con le altre corde. Il parametro gmi moltiplica il segnale proveniente a i-esima corda specificato dall’indirizzo di memoria &gmi. Una volta creato l’oggetto StringModel, utilizzando la funzione membro Outcoup o equivalentemente cu, è possibile ottenere l’indirizzo di memoria che conterrà i dati per l’accoppiamento; quindi dopo dichiarazione delle corde, la funzione incoup(…), provvede alla connessione degli accoppiamenti, ad esempio dal listato unit1.cpp

    Procsamp(int *datain) pone all’ingresso del modello l’intero contenuto all’indirizzo di datain, e restituisce il dato processato. Tratto dal programma delle sei corde

    Note(float nota), impostando la lunghezza delle linee di ritardo frazionate, stabilisce la frequenza della fondamentale della nota che verrà prodotta. L’argomento è di tipo float in quanto è utilizzato dall’interpolatore per stabilire la propria posizione lungo la linea di ritardo e per frazionare il ritardo unitario. Ad esempio con la funzione strx.Note(15) si imposta per la sintesi di un Do3 (C3), dichiarando strx.Note(15.5), la fondamentale prodotta sarà circa un C3+50 cent , ovvero una nota compresa tra Do3 e Re3; Si osserva che la parte decimale della nota impostata non coincide con i cent, in quanto l’interpolazione non avviene in modo lineare con il parametro di controllo.

    Bend(float nota), come Note definisce la lunghezza della corda, ma non agisce sulle variabili private del oggetto, provoca variazioni solo temporanee, questa funzione è stata utilizzata nel programma con l’ausilio della variabile pubblica note, che restituisce il float impostato con Note. Tratto dal listato unit15.cpp, per la realizzazione del (bending) tiraggio di una corda.
     

                    void __fastcall TForm15::TrackBar14Change(TObject *Sender)

    {
    faux=str2.note+((TrackBar14->Position)*0.02);
    if (faux>12)str2.Bend(faux);
    }
    Pluckpos(int nodo) fissa la posizione dell’eccitazione, (nodo=0) eccitazione al ponte, (nodo=50), eccitazione a metà corda.

    Ingain(float gain) permette di impostare il fattore moltiplicativo dei dati in ingresso alla corda.
     
     


    ______________________________

    Pagina iniziale