6 minute read

Documentazione dell’Analizzatore e dei Calcoli di Durata

1. Funzionamento dell’Analizzatore nel Delta-Engine

L’Analizzatore nel sistema Delta-Engine è un componente fondamentale che monitora, traccia e registra l’evoluzione temporale della composizione generativa. È implementato principalmente attraverso due strumenti Csound:

  1. instr Analizzatore - Esegue analisi in tempo reale durante la generazione
  2. instr AnalisiFinale - Esegue analisi finale e genera reportistica al termine della composizione

1.1 Analizzatore in Tempo Reale

Lo strumento Analizzatore viene avviato all’inizio della composizione con il comando alwayson "Analizzatore" e rimane attivo per tutta la durata della sessione. Le sue funzioni principali sono:

  • Monitoraggio degli eventi attivi: Tiene traccia di quanti eventi sonori sono attivi simultaneamente in un dato momento, permettendo di calcolare la densità o “sovrapposizione” degli eventi.
  • Campionamento periodico: Campiona lo stato del sistema a intervalli regolari (10Hz) per registrare l’evoluzione temporale della composizione.
  • Comunicazione con il Comportamento: Condivide informazioni sulla sovrapposizione degli eventi attraverso variabili globali che vengono utilizzate dai Comportamenti per auto-regolarsi.
instr Analizzatore
    ; Analisi della sovrapposizione di eventi - eseguita a k-rate 
    kTrig metro 10  ; 10 Hz per avere una buona risoluzione temporale
    if kTrig == 1 then
        ; Ottieni tempo corrente
        kCurrentTime timeinsts
        
        ; Calcolo eventi attivi in questo momento
        kActiveEventsCount = 0
        
        ; Analisi delle tabelle di eventi
        kEventIdx = 0
        while kEventIdx < gi_Index do  ; gi_Index contiene il numero totale di eventi creati
            kAttackTime table kEventIdx, gi_eve_attacco
            kDuration table kEventIdx, gi_eve_durata
            
            ; Verifica se l'evento è attualmente attivo
            if kAttackTime <= kCurrentTime && kAttackTime + kDuration >= kCurrentTime then
                kActiveEventsCount += 1
            endif
            
            kEventIdx += 1
        od
        
        ; Aggiorna la variabile globale per comunicare con il Comportamento
        gk_current_overlap = kActiveEventsCount
        
        ; Memorizza il conteggio degli eventi attivi e il timestamp
        tabw kActiveEventsCount, gk_analysis_index, gi_analysis_active_events
        tabw kCurrentTime, gk_analysis_index, gi_analysis_timepoints
        
        ; Avanzamento ciclico nell'indice della tabella
        gk_analysis_index = (gk_analysis_index + 1) % gi_analysis_buffer_size
    endif

L’Analizzatore inoltre crea e aggiorna una “memoria compositiva” che tiene traccia dell’evoluzione temporale della composizione su una scala più ampia:

    kMemTrig metro 1/gi_memory_resolution
    if kMemTrig == 1 then
        kCurrentTime timeinsts
        kMemIdx = int(kCurrentTime / gi_memory_resolution)
        
        if kMemIdx >= 0 && kMemIdx < gi_memory_size then
            tabw gk_current_overlap, kMemIdx, gi_memory_overlap
            tabw kActiveEventsCount, kMemIdx, gi_memory_events
        endif
    endif

1.2 Analisi Finale

Lo strumento AnalisiFinale viene eseguito al termine della composizione e si occupa di:

  • Esportare i dati raccolti in file CSV
  • Calcolare statistiche sui dati raccolti
  • Generare rappresentazioni grafiche attraverso script Python esterni
  • Fornire un riassunto dell’evoluzione compositiva
instr AnalisiFinale
    ; Crea la directory per i risultati
    iRes system_i 1, "mkdir -p ./docs/analysis", 0
    
    ; Esporta i dati di sovrapposizione in CSV
    SdataFile = "docs/analysis/overlap_data.csv"
    fprints SdataFile, "time,active_events\n"
    
    ; ... [codice per l'esportazione dei dati] ...
    
    ; Calcola e stampa statistiche di base
    iMaxOverlap = 0
    iOverlapSum = 0
    ; ... [calcolo delle statistiche] ...
    
    ; Avvia automaticamente l'analisi Python tramite make
    prints "\nAvvio dell'analisi Python...\n"
    iAnalysisRes system_i 1, "make analyze-all", 0
endin

2. UDO per il Calcolo della Durata nel Comportamento

Nel ciclo while all’interno dello strumento Comportamento, vengono utilizzati diversi UDO (User-Defined Opcodes) per calcolare la durata degli eventi. I più significativi sono:

2.1 analyzeCompositionMemory

Questo UDO analizza un intervallo specifico della memoria compositiva per estrarre informazioni sulla densità degli eventi:

opcode analyzeCompositionMemory, iiii, ii
    iStartTime, iEndTime xin
    
    ; Calcola indici nella tabella di memoria
    iStartIdx = int(iStartTime / gi_memory_resolution)
    iEndIdx = int(iEndTime / gi_memory_resolution)
    
    ; Assicurati che gli indici siano entro i limiti
    iStartIdx = limit(iStartIdx, 0, gi_memory_size-1)
    iEndIdx = limit(iEndIdx, 0, gi_memory_size-1)
    
    ; Inizializza contatori
    iSumOverlap = 0
    iMaxOverlap = 0
    iActivePoints = 0
    iCount = 0
    
    ; Analizza il range temporale
    iIdx = iStartIdx
    while iIdx <= iEndIdx do
        iOverlap table iIdx, gi_memory_overlap
        
        if iOverlap > 0 then
            iSumOverlap += iOverlap
            iMaxOverlap = max(iMaxOverlap, iOverlap)
            iActivePoints += 1
        endif
        
        iCount += 1
        iIdx += 1
    od
    
    ; Calcola valori aggregati
    iAvgOverlap = (iActivePoints > 0) ? iSumOverlap / iActivePoints : 0
    iDensity = (iCount > 0) ? iActivePoints / iCount : 0
    
    xout iAvgOverlap, iMaxOverlap, iDensity, iCount
endop

Questo UDO restituisce quattro valori:

  1. iAvgOverlap - Sovrapposizione media nell’intervallo
  2. iMaxOverlap - Sovrapposizione massima nell’intervallo
  3. iDensity - Percentuale di punti attivi nell’intervallo
  4. iCount - Numero totale di punti analizzati

2.2 suggestDurationFactor

Questo UDO utilizza l’analisi della memoria compositiva per suggerire un fattore di durata adattivo:

opcode suggestDurationFactor, i, iii
    iStartTime, iEndTime, iRitmoCorrente xin
    
    ; Analizza la memoria compositiva nel range specificato
    iAvgOverlap, iMaxOverlap, iDensity, iSampleCount = analyzeCompositionMemory(iStartTime, iEndTime)
    
    ; Se non abbiamo abbastanza dati o il range è vuoto, usa valori predefiniti
    if iSampleCount < 2 || iDensity < 0.05 then
        iSuggestedFactor = 1.0  ; Valore neutro
        goto end
    endif
    
    ; Altrimenti, suggerisci un fattore basato sull'analisi
    iMaxReference = 8  ; Livello di riferimento per la sovrapposizione massima
    iAvgReference = 3  ; Livello di riferimento per la sovrapposizione media
    
    ; Calcola un fattore basato sia sul massimo che sulla media
    iFactorFromMax = 1.0 + (iMaxReference - iMaxOverlap) * 0.1
    iFactorFromAvg = 1.0 + (iAvgReference - iAvgOverlap) * 0.2
    
    ; Combina i fattori dando più peso alla media
    iSuggestedFactor = (iFactorFromMax + iFactorFromAvg * 2) / 3
    
    ; Limita il fattore all'intervallo desiderato
    iSuggestedFactor = limit(iSuggestedFactor, 1.0, iRitmoCorrente)
    
    end:
    xout iSuggestedFactor
endop

Questo UDO è fondamentale per l’auto-regolazione del sistema: se la sovrapposizione di eventi è superiore ai valori di riferimento, suggerisce durate più brevi; se è inferiore, suggerisce durate più lunghe.

2.3 Applicazione nel Comportamento

Nel ciclo while dell’istrumento Comportamento, questi UDO vengono utilizzati per calcolare la durata di ogni evento:

; Calcola il lookback time (tempo da analizzare per l'adattamento)
iCurrentTime = i_time + i_CAttacco
iLookbackTime = max(0, iCurrentTime - 30)  ; Guarda agli ultimi 30 secondi

; Ottieni il fattore di durata suggerito
i_OverlapFactor = suggestDurationFactor(iLookbackTime, iCurrentTime, i_RitmoCorrente)

; Durante la fase di bootstrap, utilizza durate maggiori
if gi_Index < 10 then ; Per i primi 10 eventi
    prints "MODALITÀ BOOTSTRAP: Forzatura durata evento\n"
    i_DurEvento = (i_DurataArmonica/i_RitmoCorrente) * 3.0
else
    ; Calcola la durata dell'evento con il fattore di adattamento
    i_DurEvento = (i_DurataArmonica/i_RitmoCorrente) * i_OverlapFactor
endif

3. Funzionamento del Ciclo di Generazione dei Comportamenti

Il ciclo principale che genera i comportamenti si trova nello strumento Comportamento e funziona così:

  1. Legge i parametri iniziali (ritmi, posizioni, ottave, ecc.)
  2. Inizia un ciclo che continua finché non viene raggiunta la durata desiderata
  3. Per ogni iterazione:
    • Calcola il ritmo corrente (o lo genera usando la funzione NonlinearFunc se necessario)
    • Calcola il tempo di attacco
    • Calcola l’ampiezza usando calcAmpiezza
    • Calcola la frequenza usando calcFrequenza
    • Determina la durata dell’evento in base all’analisi della sovrapposizione
    • Memorizza i parametri nelle tabelle globali
    • Pianifica l’evento sonoro
while i_time < i_Durata do
   ; Determina il ritmo corrente
   if i_Index < i_LenRitmi then
      i_RitmoCorrente tab_i i_Index, gi_comp_temp_ritmi
   else 
      i_Vecchio_Ritmo tab_i i_Index-1, gi_comp_temp_ritmi
      i_RitmoCorrente NonlinearFunc i_Vecchio_Ritmo
      tabw_i i_RitmoCorrente, i_Index, gi_comp_temp_ritmi
   endif
   
   ; ... [calcolo dei parametri] ...
   
   ; Calcola la durata dell'evento
   i_OverlapFactor = suggestDurationFactor(iLookbackTime, iCurrentTime, i_RitmoCorrente)
   i_DurEvento = (i_DurataArmonica/i_RitmoCorrente) * i_OverlapFactor
   
   ; ... [memorizzazione e scheduling] ...
   
   i_Index += 1
   gi_Index += 1
   i_time = i_Pfield2 + i_DurEvento
od

4. Potenziali Miglioramenti

Per generare un nuovo comportamento a partire da quello iniziale, si potrebbero apportare i seguenti miglioramenti all’analizzatore:

  1. Analisi dei pattern emergenti: Rilevare schemi ricorrenti nella sovrapposizione e nella generazione dei ritmi.
  2. Clustering temporale: Identificare sezioni con caratteristiche simili e utilizzarle come semi per nuovi comportamenti.
  3. Apprendimento adattivo: Modellare come i fattori di durata influenzano l’evoluzione della composizione e utilizzare questi modelli per migliorare i suggerimenti.
  4. Transizioni tra comportamenti: Implementare logiche per transizioni fluide tra diversi comportamenti basate sullo stato corrente del sistema.
  5. Memoria a lungo termine: Estendere l’analisi oltre la semplice sovrapposizione per includere pattern melodici, ritmici e armonici.

Questi miglioramenti permetterebbero al sistema di evolvere in modo più complesso e organico, generando comportamenti che non sono semplicemente variazioni casuali, ma risposte adattive al contesto musicale emergente.