Pensa a questo da una prospettiva di elaborazione.
La voce è l'output predefinito integrato, ottimizzato da zero per l'efficienza energetica e l'efficienza del ciclo di istruzioni nel sistema operativo e nell'hardware.
Ora considera la possibilità di replicare la musica su uno strumento. Uno strumento è un hardware esterno che non è mai stato ottimizzato nel sistema operativo o nell'hardware su cui viene eseguito. Nel mondo dei computer, l'utilizzo di nuove periferiche implica il caricamento dei driver (plug-in a livello di sistema operativo) o l'utilizzo di un programma fornito con le periferiche (interfaccia a livello di applicazione).
Le persone con un tono perfetto potrebbero essere paragonato ad avere driver a livello di sistema operativo efficienti per la nuova periferica (strumento). Buono, sebbene più lento dell'ottimizzazione hardware.
Tutti gli altri (senza intonazione perfetta) potrebbero essere paragonati all'utilizzo di un'interfaccia a livello di applicazione (programma specifico) per controllare la periferica (strumento). Prestazioni lente e peggiori rispetto ai driver a livello di sistema operativo o all'ottimizzazione dell'hardware.
In alternativa, considera una prospettiva orientata ai dati.
L'ingresso audio è fondamentalmente analogico e, a scopo di discussione, presume che il brain memorizza l'ingresso audio in un semplice formato analogico (simile a un file WAV sul computer). L'output vocale accetta nativamente lo stesso formato analogico, il che significa che non c'è quasi nessun sovraccarico di elaborazione nell'eco di ciò che hai appena ascoltato.
Pensa alle note musicali come un formato digitale (logico): una sequenza di marcatori di inizio / fine nota . Per suonare uno strumento, devi eseguire il seguente algoritmo. Per motivi di semplicità, supponi di suonare solo 1 strumento alla volta.
instrument D = getCurrentInstrument (). Open () P = NoteInputStream (AnalogAudioInputStream (input song), D) mentre true: nota N = P.nextNoteMarker () se N == null allora esci altrimenti se N.isBegin quindi D.holdNoteAfterDelay (N, N.delay) altrimenti se N.isEnd quindi D.releaseNoteAfterDelay (N, N.delay)
Sembra abbastanza semplice in pseudocodice. Ma cosa sta succedendo veramente? La complessità è nelle funzioni API sopra.
getCurrentInstrument () è una funzione che restituisce un riferimento allo strumento nelle tue mani. Relativamente semplice. La funzione instrument.open () è un'altra cosa. Questo carica i driver per lo strumento - in altri termini, devi "ricordare" come suonare lo strumento. Ciò include la mappatura mentale delle note logiche a tutto ciò che devi fare sullo strumento per produrre la nota (probabilmente una tabella di ricerca inversa). Se lo strumento include il mantenimento e il rilascio di molte note contemporaneamente (come un pianoforte), ciò include anche capire come ottimizzare le dita per tenere premuto un insieme di note. Pertanto, instrument.open () richiede molta potenza di elaborazione e memoria a breve termine (RAM).
AnalogAudioInputStream (audioInput) accetta l'ingresso audio analogico e lo converte in un "flusso" di dati.
NoteInputStream (analogInput, instrument) prende il suddetto flusso audio analogico e uno strumento, estraendo le note per lo strumento specificato dall'ingresso analogico. In questo passaggio entra in gioco l'altezza perfetta, identificando lo strumento "principale" e mappandone la frequenza alle note logiche in tempo reale.
Ogni nota è rappresentata come chiave, ottava, ritardo prima dell'elaborazione e inizio / end flag che rappresenta se la nota rappresenta un evento hold-down o stop-holding-down.
Riproduzione dell'ingresso analogico sullo strumento: eseguire il loop sul set di nodi estratti e tenere premuto / rilasciare sullo strumento come dettato. La complessità delle operazioni di attesa / rilascio delle note dipende ampiamente dallo strumento e ovviamente potrebbe non riuscire se si esauriscono le dita o se l'input è ridicolo.