LPDIRECTSOUND gSndMain = NULL;
LPDIRECTSOUNDBUFFER gSndNote[QMAX_CAMPIONI_NOTE] = { NULL };
LPDIRECTSOUNDBUFFER gNote[QMAX_BUFFERS_NOTE] = { NULL };
/*==============================================================================
All'inizio dell'esecuzione del programma, con InizializzaSonoro() carico i suoni
che mi occorrono predisponendo con CreateSoundBuffer() un buffer per ciascuno
dei suoni campionati che prevedo di usare. Quegli otto buffer che "nascono" dai
suoni campionati hanno ciascuno la sua copia "fisica" dei dati. A me, però,
occorrono 25 suoni indipendenti, per coprire due ottave cromatiche complete.
Creo quindi con DuplicateSoundBuffer() tre "alias" per ciascuno dei buffer che
ho appena caricato (per l'ultimo, in effetti, ne creo quattro, ma e'
irrilevante).
Per come agisce DuplicateSoundBuffer(), gli "alias" creati non dispongono di
dati propri, ma fanno riferimento ai dati in memoria gestiti dai buffer
originali, operando su di essi. Fin qui tutto bene, il meccanismo l'ho compreso.
==============================================================================*/
bool InizializzaSonoro( HWND hwnd ) {
DWORD esito;
int i, j;
// ... codice per inizializzare DirectSound ...
// NOTA:
// DSLoadSoundBuffer() e' una funzione che ho trovato tra gli esempi
// dell'SDK di DirectX 7; crea un buffer statico con CreateSoundBuffer() e
// ne "riempie" lo spazio di memoria abbinato usando i dati caricati da una
// risorsa di tipo WAV
for( i=0; i<QMAX_CAMPIONI_NOTE; ++i ) {
gSndNote[i] = DSLoadSoundBuffer( gSndMain,MAKEINTRESOURCE(IDR_NOTA+i) );
if( NULL == gSndNote[i] ) return false;
}
// i dati dei suoni sono in memoria, ora imposto, a partire dagli otto
// (QMAX_CAMPIONI_NOTE vale 8) buffers gSndNote[], i venticinque (QMAX_NOTE
// vale 25) alias che servono per le due ottave cromatiche
esito = 0; // uso questo per una verifica "cumulativa" dei risultati
// le prime tre note, abbinate al primo campione audio
esito += DS_OK==gSndMain->DuplicateSoundBuffer( gSndNote[0], gNote+0 );
esito += DS_OK==gNote[0]->SetFrequency( 41600 );
esito += DS_OK==gSndMain->DuplicateSoundBuffer( gSndNote[0], gNote+1 );
esito += DS_OK==gNote[1]->SetFrequency( 44100 ); // originale
esito += DS_OK==gSndMain->DuplicateSoundBuffer( gSndNote[0], gNote+2 );
esito += DS_OK==gNote[2]->SetFrequency( 46700 );
// le tre note successive, abbinate al secondo campione audio
esito += DS_OK==gSndMain->DuplicateSoundBuffer( gSndNote[1], gNote+3 );
esito += DS_OK==gNote[3]->SetFrequency( 41600 );
esito += DS_OK==gSndMain->DuplicateSoundBuffer( gSndNote[1], gNote+4 );
esito += DS_OK==gNote[4]->SetFrequency( 44100 ); // originale
esito += DS_OK==gSndMain->DuplicateSoundBuffer( gSndNote[1], gNote+5 );
esito += DS_OK==gNote[5]->SetFrequency( 46700 );
// ... eccetera, fino ad esaurire gli otto campioni, arrivando a gNote[24]
return (50==esito); // 25 note per due passaggi ciascuna: 50 passaggi
}
/*==============================================================================
In SuonaNota(), uso i venticinque alias dell'array gNote[] come strumento
musicale (un glockenspiel con estensione di due ottave cromatiche).
Dalla documentazione, vengo a sapere che DirectSound potrebbe liberare senza
preavviso la memoria abbinata a uno qualsiasi degli otto buffer dell'array
gSndNote[], memoria alla quale fanno riferimento anche i 25 "alias" dell'array
gNote[] da essi ricavati. IN QUEL CASO, sebbene l'errore venga segnalato da
gNote[iNota], occorrerebbe ricreare un buffer che non e' in carico a
gNote[iNota], bensi' all'elemento di gSndNote[] al quale si appoggia
quell'alias.
Ecco quindi LA DOMANDA: il ripristino si fa con gNote[iNota]->Restore() (usando
quindi direttamente l'alias) o bisogna risalire al buffer dell'array gSndNote[]
dal quale e' stato ricavato gNote[iNota] e usare sottoporre QUELLO a Restore()?
E in questo secondo caso, dopo avere ricreato e ricaricato i dati in gSndNote[],
occorre compiere qualche operazione sull'alias gNote[iNota] per aggiornare il
collegamento con il buffer originario o e' un processo "automatico"?
==============================================================================*/
void SuonaNota( int iNota ) {
if( !gSuoniInizializzati ) return;
if( iNota<0 || iNota>=QMAX_BUFFERS_NOTE ) return;
// ... ci sono parti di codice che non c'entrano
// nulla con le domande e che taglio per brevita'
HRESULT hr = gNote[iNota]->Play( 0, 0, 0 );
if( DSERR_BUFFERLOST == hr ) {
// ahi! il buffer e' stato demolito da DirectSound,
// e questo ci porta al nodo della questione
// occorre ricostituire i dati tramite il buffer originario...
hr = DSReloadSoundBuffer( gNote[iNota],
MAKEINTRESOURCE(IDR_CAMPIONENOTA+iNota/BUFFER_PER_NOTA) );
// ...oppure ricostituirli tramite il suo "alias"...
hr = DSReloadSoundBuffer( gSndNote[iNota/BUFFER_PER_NOTA],
MAKEINTRESOURCE(IDR_CAMPIONENOTA+iNota/BUFFER_PER_NOTA) );
// ...aggiungendo magari qualche altra operazione per ripristinare
// il collegamento tra il buffer originario e il suo "alias"?
// al termine del ripristino del buffer, possiamo eseguire il suono
if( DS_OK == hr ) hr = gSnd[iNota]->Play( 0, 0, 0 );
}
}