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);
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.
L’oggetto StringModelDelayLine::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]);
}
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.
|
|
|
|
|
|
|
A#1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Dato che si vuole sintetizzare sei corde di una chitarra acustica, secondo la normale accordatura, nella definizione delle corde il parametro note deve valere.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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.
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)
Ingain(float gain) permette di impostare il fattore moltiplicativo
dei dati in ingresso alla corda.