Sistema di Transizione di Stati
Sistema di Transizione di Stato per Delta-Engine
Questo documento descrive il sistema di transizione di stato implementato per Delta-Engine, un framework di composizione algoritmica basato su Csound.
Visione d’Insieme
Il sistema di transizione di stato permette alla composizione di evolversi in modo organico attraverso diversi stati musicali definiti da tre dimensioni principali:
- Densità - Numero di eventi sonori attivi simultaneamente
- Registro - Distribuzione dei suoni nelle ottave
- Movimento - Grado di attività spaziale
Ogni dimensione è suddivisa in tre stati (0, 1, 2), creando uno spazio di 27 possibili stati complessivi.
Componenti Principali
Il sistema è implementato attraverso due file UDO (User Defined Opcodes) principali:
stateMapping.udo
- Converte gli stati astratti in parametri concretistateTransition.udo
- Gestisce le transizioni tra stati diversi
stateMapping.udo
Questo file contiene opcode per mappare gli stati (indici numerici) in parametri concreti utilizzati nella generazione degli eventi sonori.
mapStateToParameter
Converte un indice di stato in un range di valori per un parametro specifico.
opcode mapStateToParameter, ii, iS
iStateIndex, SparamType xin
iMin = 0
iMax = 0
if strcmp(SparamType, "density") == 0 then
; Legge le soglie direttamente dalla tabella density_thresholds
iLowerBound tab_i iStateIndex, gi_density_thresholds
iUpperBound tab_i iStateIndex+1, gi_density_thresholds
; Aggiunge un piccolo margine per evitare valori di confine
iMin = iLowerBound + 0.1
; Limita il massimo a un valore ragionevole
iMax = (iUpperBound > 100) ? 12 : iUpperBound - 0.1
elseif strcmp(SparamType, "register") == 0 then
; Legge le soglie dalla tabella register_thresholds
iLowerBound tab_i iStateIndex, gi_register_thresholds
iUpperBound tab_i iStateIndex+1, gi_register_thresholds
; Converte i valori normalizzati (0-1) in valori di ottave (1-10)
iMin = 1 + iLowerBound * ($OTTAVE - 1)
iMax = 1 + iUpperBound * ($OTTAVE - 1)
elseif strcmp(SparamType, "movement") == 0 then
; Legge le soglie dalla tabella movement_thresholds
iLowerBound tab_i iStateIndex, gi_movement_thresholds
iUpperBound tab_i iStateIndex+1, gi_movement_thresholds
; Inversione dei valori per il movimento (valori ritmici bassi = più movimento)
iMoveLow = 1 - iUpperBound
iMoveHigh = 1 - iLowerBound
; Scala i valori al range di ritmi appropriato (1-20)
iMin = 1 + iMoveLow * 19
iMax = 1 + iMoveHigh * 19
endif
; Arrotonda i valori per maggiore chiarezza
iMin = round(iMin)
iMax = round(iMax)
xout iMin, iMax
endop
Parametri di Input:
iStateIndex
- Indice dello stato (0, 1, o 2)SparamType
- Tipo di parametro (“density”, “register”, o “movement”)
Output:
iMin
- Valore minimo del rangeiMax
- Valore massimo del range
Funzionamento:
- Legge i valori di soglia dalle tabelle appropriate
- Calcola i valori minimi e massimi in base al tipo di parametro
- Applica logiche specifiche per ciascun tipo di parametro (es. inversione per il movimento)
- Arrotonda i valori e li restituisce come range
generateRhythmsForState
Genera una tabella di valori ritmici appropriati per un dato stato di movimento.
opcode generateRhythmsForState, i, i
iTargetMovement xin
iTblSize = 5 ; Dimensione della tabella ritmica
iTableNum ftgen 0, 0, iTblSize, -2, 0
; Ottiene i range di valori appropriati dalle soglie di movimento
iMinVal, iMaxVal mapStateToParameter iTargetMovement, "movement"
; Genera valori ritmici appropriati
iIdx = 0
while iIdx < iTblSize do
iRhythmVal random iMinVal, iMaxVal
iRhythmVal = round(iRhythmVal) ; Arrotonda al valore intero più vicino
; Assicura che non ci siano valori ritmici nulli o negativi
if iRhythmVal < 1 then
iRhythmVal = 1
endif
tabw_i iRhythmVal, iIdx, iTableNum
iIdx += 1
od
xout iTableNum
endop
Parametri di Input:
iTargetMovement
- Indice dello stato di movimento target (0, 1, o 2)
Output:
iTableNum
- Numero identificativo della tabella generata
Funzionamento:
- Crea una nuova tabella di dimensione predefinita
- Ottiene il range di valori ritmici appropriato utilizzando
mapStateToParameter
- Genera valori ritmici casuali all’interno di questo range
- Restituisce l’identificatore della tabella generata
stateTransition.udo
Questo file contiene opcode per gestire le transizioni tra stati diversi.
initTransitionMatrix
Inizializza la matrice di transizione con probabilità predefinite.
opcode initTransitionMatrix, 0, 0
; Per ogni stato possibile (27 stati totali = 3×3×3)
iStateIdx = 0
while iStateIdx < 27 do
; Scomponiamo l'indice nei suoi componenti
iCurrentDensity = int(iStateIdx / 9)
iRemainder = iStateIdx % 9
iCurrentRegister = int(iRemainder / 3)
iCurrentMovement = iRemainder % 3
; Per ogni possibile stato successivo
iNextStateIdx = 0
while iNextStateIdx < 27 do
; Scomponiamo l'indice del prossimo stato
iNextDensity = int(iNextStateIdx / 9)
iNextRemainder = iNextStateIdx % 9
iNextRegister = int(iNextRemainder / 3)
iNextMovement = iNextRemainder % 3
; Calcoliamo la "distanza" tra stati (quanti parametri cambiano)
iChanges = 0
if iCurrentDensity != iNextDensity then
iChanges += 1
endif
if iCurrentRegister != iNextRegister then
iChanges += 1
endif
if iCurrentMovement != iNextMovement then
iChanges += 1
endif
; Assegniamo probabilità basate sulla distanza
iProb = 0
if iChanges == 0 then
iProb = 0.4 ; 40% probabilità di rimanere nello stesso stato
elseif iChanges == 1 then
iProb = 0.3 ; 30% probabilità di cambiare un solo parametro
elseif iChanges == 2 then
iProb = 0.2 ; 20% probabilità di cambiare due parametri
else
iProb = 0.1 ; 10% probabilità di cambiare tutti i parametri
endif
; Salva la probabilità nella matrice
tabw_i iProb, iStateIdx*27+iNextStateIdx, gi_transition_matrix
iNextStateIdx += 1
od
; Normalizza le probabilità per assicurarsi che sommino a 1
iSum = 0
iNextIdx = 0
while iNextIdx < 27 do
iProb tab_i iStateIdx*27+iNextIdx, gi_transition_matrix
iSum += iProb
iNextIdx += 1
od
if iSum > 0 then
iNextIdx = 0
while iNextIdx < 27 do
iProb tab_i iStateIdx*27+iNextIdx, gi_transition_matrix
iNormProb = iProb / iSum
tabw_i iNormProb, iStateIdx*27+iNextIdx, gi_transition_matrix
iNextIdx += 1
od
endif
iStateIdx += 1
od
endop
Funzionamento:
- Itera attraverso tutti i 27 stati possibili
- Per ogni stato, assegna probabilità di transizione verso tutti gli altri stati
- Le probabilità sono assegnate in base alla “distanza” tra stati:
- Rimanere nello stesso stato: 40%
- Cambiare un parametro: 30%
- Cambiare due parametri: 20%
- Cambiare tutti i parametri: 10%
- Normalizza le probabilità per assicurarsi che sommino a 1 per ogni stato
selectNextState
Seleziona il prossimo stato in base alle probabilità definite nella matrice di transizione.
opcode selectNextState, iii, iii
iCurrentDensity, iCurrentRegister, iCurrentMovement xin
; Calcola l'indice di base nella matrice di transizione
iStateIdx = (iCurrentDensity * 9) + (iCurrentRegister * 3) + iCurrentMovement
; Genera un numero casuale
iRand random 0, 1
; Seleziona il prossimo stato in base alla probabilità cumulativa
iCumulativeProb = 0
iNextStateIdx = 0
iIdx = 0
while iIdx < 27 do
iTransProb tab_i iStateIdx*27+iIdx, gi_transition_matrix
iCumulativeProb += iTransProb
if iRand < iCumulativeProb then
iNextStateIdx = iIdx
igoto found_next
endif
iIdx += 1
od
found_next:
; Converti l'indice nei parametri di stato
iNextDensity = int(iNextStateIdx / 9)
iRemainder = iNextStateIdx % 9
iNextRegister = int(iRemainder / 3)
iNextMovement = iRemainder % 3
xout iNextDensity, iNextRegister, iNextMovement
endop
Parametri di Input:
iCurrentDensity
- Stato corrente della densità (0-2)iCurrentRegister
- Stato corrente del registro (0-2)iCurrentMovement
- Stato corrente del movimento (0-2)
Output:
iNextDensity
- Prossimo stato della densitàiNextRegister
- Prossimo stato del registroiNextMovement
- Prossimo stato del movimento
Funzionamento:
- Calcola l’indice dello stato corrente nella matrice di transizione
- Genera un numero casuale
- Utilizza un metodo di “probabilità cumulativa” per selezionare il prossimo stato
- Converte l’indice del prossimo stato nei suoi componenti
- Restituisce i componenti del prossimo stato
Tabelle di Supporto
Il sistema si basa su diverse tabelle di soglia definite in first.orc
:
Tabelle di Soglia
; Definisce le soglie per i diversi stati
gi_density_thresholds ftgen 0, 0, 4, -2, 0, 3, 7, 999 ; Sparse, Medium, Dense
gi_register_thresholds ftgen 0, 0, 4, -2, 0, 0.3, 0.7, 1 ; Low, Mid, High
gi_movement_thresholds ftgen 0, 0, 4, -2, 0, 0.2, 0.5, 1 ; Static, Moderate, Dynamic
Queste tabelle definiscono i confini tra i diversi stati per ciascun parametro.
Matrice di Transizione
; Matrice di transizione per le probabilità di passaggio tra stati
gi_transition_matrix ftgen 0, 0, 27*27, -2, 0
Tabelle di Storia degli Stati
; Storia recente degli stati
gi_state_history_density ftgen 0, 0, gi_state_history_size, -2, 0
gi_state_history_register ftgen 0, 0, gi_state_history_size, -2, 0
gi_state_history_movement ftgen 0, 0, gi_state_history_size, -2, 0
Utilizzo nel Sistema
Il sistema di transizione di stato è integrato nel ciclo compositivo come segue:
- L’
Analizzatore
misura parametri musicali in tempo reale determineCurrentState
classifica questi parametri in stati discreti- Le tabelle di storia vengono aggiornate con i nuovi stati
GeneraComportamenti
legge lo stato corrente e seleziona uno stato target- I parametri dello stato target vengono convertiti in valori concreti
- I comportamenti vengono generati usando questi valori
- Gli eventi sonori creati influenzano a loro volta l’analisi
Questo ciclo di feedback crea un’evoluzione compositiva organica e strutturata.
Note di Implementazione
- Il sistema è progettato per essere flessibile: le soglie possono essere modificate per creare diversi profili compositivi.
- Le probabilità di transizione possono essere adattate per favorire transizioni più graduali o più contrastanti.
- Il sistema mantiene una coerenza tra la classificazione degli stati e la generazione dei parametri utilizzando le stesse tabelle di soglia per entrambi i processi.