• Non ci sono risultati.

3.2 “Back to the Future”

3.9. pCM+: Il Framework

Come già anticipato nel paragrafo 3.6, pCM+ sfrutta la programmazione generica insieme alla me- taprogrammazione per aumentare la flessibilità nel rapporto tra il codice utente e pCM+ stesso. Inoltre, tali tecniche di programmazione hanno permesso al framework di separare in modo netto le responsabilità del utente da quelle del framework stesso, riducendo al minimo indispensabile le prime.

In questo paragrafo viene esposto il framework pCM+. L’esposizione definirà in termini di pseudo- signature tutti i concetti (paragrafo 3.6.1) che il codice utente deve definire per poter utilizzare il framework.

Lungo i sottoparagrafi che seguono sarà presentato un esempio completo, che dovrebbe chiarire quanto qui esposto.

3.9.1. Inizializzazione e terminazione del framework

Ovviamente, la prima responsabilità del codice utente è l’inizializzazione del framework. pCM+ implementa la procedura di inizializzazione per mezzo del singleton15 [Gamma95] Init (definito

nel file header <pcm+/Init.h>). Tale classe è un template, il cui parametro è il tipo dell’orchestra

15 Tutti i singleton di pCM+ sono implementati per mezzo della host class SingletonHolder fornita dal framework

manager definito dall’utente. L’istanziamento del singleton Init causa l’istanziamento dell’orche- stra manager.

L’istanziamento del singleton Init non è sufficiente per inizializzare completamente pCM+: infatti, affinchè l’inizializzazione sia completata, occorre invocare il metodo Initialize(), che inizializza la libreria Intel TBB, che come sappiamo è utilizzata da pCM+. Tale metodo prende in ingresso un argomento opzionale, che specifica il numero di thread da utilizzare (tale valore è passato al task_scheduler_init di TBB): come consigliato dalla specifica di TBB, tale argomento dovrebbe essere specificato soltanto quando si vogliono svolgere studi di scalabilità durante lo sviluppo. Il fatto che dall’invocazione del metodo Initialize() dipenda l’inizializzazione di TBB rende di cru- ciale importanza che tale invocazione avvenga prima dell’avvio del processo di rendering.

La terminazione del framework può avvenire o in modo implicito durante la terminazione del pro- gramma, o se il codice utente abbia l’esigenza di terminare pCM+ in modo esplicito è sufficiente distruggere il singleton.

Per agevolare l’inizializzazione e la terminazione, pCM+ definisce le seguenti tre macro:

#define PCM_INIT( OrcMngTypeName ) pcm::Init< OrcMngTypeName >::Instance( ).Initialize( ); #define PCM_INIT_DEBUG( OrcMngTypeName, num_threads ) \

pcm::Init< OrcMngTypeName >::Instance( ).Initialize( num_threads ); #define PCM_TERMINATE( OrcMngTypeName ) \

Loki::DeletableSingleton< pcm::Init< OrcMngTypeName > >::GracefulDelete();

Listato 3.1: Macro di utilità per lʼinizializzazione e la terminazione di pCM+ definite nel file header <pcm+/Init.h>.

Il parametro OrcMngTypeName è il tipo dell’orchestra manager. PCM_INIT_DEBUG permette di specifica il numero di thread con cui si vuole limitare il supporto al parallelismo (come lascia intendere il nome della macro, da usarsi sono in fase di sviluppo).

3.9.2. Costanti e tipi base

È possibile controllare alcune costanti e tipi base da cui dipende l’attività di rendering e che posso- no variare da un supporto audio all’altro, modificando il file header <pcm+/Basics.h>.

In questo file sono infatti definite le seguenti costanti:

• pcm::num_channels: il numero di canali audio.

• pcm::sample_rate: la frequenza di campionamento. • pcm::frames_per_buffer: il numero di frame per buffer.

Il formato dei campioni è definito dal tipo pcm::Sample (tipicamente è un float, ma pCM+ da la possibilità di modificare il formato dei campioni a tempo di compilazione modificando, appunto, la typedef pcm::Sample).

Infine, in <pcm+/Basics.h> sono definite ulteriori costanti utili per l’attività di rendering e per lo

scope, come pi greco (π) e le frequenze (in Hz) corrispondenti alle note da Do-0 a Si-7.

3.9.3. Orchestra Manager

Nel paragrafo 3.8.4 abbiamo introdotto l’orchestra manger, le cui responsabilità affondano su quelle di dominio di pCM+, e non certo del codice utente. All’utente è lasciato il solo compito di definire il tipo concreto dell’orchestra manager. Esso è infatti implementato come un template che prende in ingresso i seguenti tre parametri:

• La lista di orchestre che lo score prevede di utilizzare durante la sua esecuzione. Ogni orchestra deve essere modello del concetto di Orchestra (vedi paragrafo 3.9.4).

• La lista dei gradi di polifonia associati a ciascuna orchestra dichiarata nella lista di orchestre. • Opzionalmente, la lista dei numeri di token che al massimo possono circolare lungo ciascuna

trollare il grado di parallelismo raggiungibile da eventuali replicazioni (FARM) introdotte dinamicamente da TBB. Quando tale lista non è specificata, pCM+ calcola (a tempo di compi- lazione) la lunghezza delle pipeline associate a ciascuna orchestra, e pone come massimo nu- mero di token tale valore, disabilitando di fatto la possibilità di replicazione da parte del sup- porto al parallelismo.

Tali liste devono essere tipi che soddisfino il cancetto di Forward Sequence16, definito dalla libreria

Boost MPL. Per agevolare l’utente nella definizione di tali liste, pCM+ definisce nel file header

<pcm+/OrcMng.h> (vedi appendice A) una serie di macro. Tale file header contiene anche la defini- zione dell’orchestra manager.

#include <pcm+/OrcMng.h> // My Orchestra Headers:

#include "LeadOrchestra.h"

// Definiamo il set di orchestre che vogliamo usare nello score.

PCM_DEFINE_ORCHESTRA_LIST_2( MyOrchestraList, LeadOrchestra, LeadOrchestra );

// Definiamo il grado della polifonia per ciascun orchestra.

PCM_DEFINE_POLYPHONY_LIST_2( MyPoplyphonieList, 1, 12 );

// Definiamo infine il tipo dell'orchestra manager.

typedef pcm::OrchestraManager< MyOrchestraList, MyPoplyphonieList > MyOrcMng;