Il presente articolo è stato tradotto automaticamente.
Nuove frontiere per l'interfaccia utente
Generazione del suono nelle applicazioni WPF
Charles Petzold
Alcune settimane fa sat un nuovo Prius Toyota mentre l'agente presso la società di noleggio autovetture spiegati i controlli non sono noti e indicatori matriciale nel dashboard. “ Stupite, ” credevo. “ Anche nel caso di una tecnologia come vecchia come l'automobile, i produttori sono continuamente ridefinizione dell'interfaccia utente. ”
Nel senso più ampio dell'interfaccia utente è il luogo dove umani e computer interagire. Sebbene il concetto sia come vecchio come tecnologia stessa, l'interfaccia utente realmente blossomed come form art solo con rivoluzione personal computer.
Solo una piccola frazione degli utenti di personal computer oggi è in grado di memorizzare i giorni prima dell'avvento di interfacce utente grafiche di Microsoft Windows e Apple Macintosh. Al momento (il mid - per tardi anni ' 80), alcuni pundits feared che standardizzazione dell'interfaccia utente potrebbe imporre un'uniformità oppressive rispetto alle applicazioni. Non era la distinzione tra maiuscole e minuscole. In alternativa, come la disponibilità dello standard controlli liberati progettisti e ai programmatori dalla necessità di scoprire la barra di scorrimento, le interfacce utente effettivamente iniziano a evolversi e diventano molto più interessante.
In questo caso, i nuovi paradigmi introdotti da Windows Presentation Foundation (WPF) hanno consentito di interfacce utente ottenere anche sofisticato. WPF fornisce una base solida di modalità grafica, animazioni e 3D verso il basso. Aggiunge che una struttura gerarchica basata sulla struttura ad albero di elementi padre e figlio e un linguaggio di markup potente nota come XAML. Il risultato è una flessibilità senza precedenti nella personalizzazione dei controlli esistenti tramite l'applicazione di modelli e la creazione di nuovi controlli da assemblare i componenti esistenti.
Ma questi nuovi concetti non sono solo per client di programmazione. Un sottoinsieme integro delle classi Microsoft .NET Framework, XAML e WPF sono diventati disponibili nella programmazione basata sul Web tramite Silverlight. Il giorno è arrivato già quando è effettivamente possibile condividere controlli personalizzati tra le applicazioni client e applicazioni Web. Si è sicuri che questa tendenza verrà continuare nelle applicazioni mobili e infine comprendono molti tipi diversi di informazioni e intrattenimento sistemi, sfruttando i vantaggi delle nuove tecnologie, ad esempio multi-touch.
Per questi motivi sta indotto che l'interfaccia utente è diventata una parte ancora più importante della programmazione delle applicazioni. In questa colonna analizzerà il potenziale della progettazione dell'interfaccia utente di WPF e Silverlight, compreso l'utilizzo di codice multipiattaforma quando possibile.
Sembra disattivato
Non è sempre possibile distinguere immediatamente scelte valida e non valido-interfaccia utente. Clippy, ovvero la graffetta anthropomorphized debuted in Microsoft Office 97, probabilmente seemed come al momento opportuno. Per questo motivo, mi concentrerò più sul potenziale tecnologici anziché di progettazione. Verrà in genere per evitare il termine “ consigliate ”. Che è una questione di cronologia e sul mercato.
Ad esempio, un ottimo case stato possibile stabilire che i computer non devono apportare parole non significative, ad eccezione di quando si sta eseguendo un video o un file audio in risposta a un comando specifico da parte dell'utente. Illustrerò per ignorare tale stricture e viene illustrato come riprodurre i suoni personalizzati in un'applicazione WPF dalla generazione di dati Wave in fase di esecuzione.
Questa funzionalità apportare suono non è ancora una parte ufficiale di .NET Framework, ma si è reso possibile dalla libreria NAudio disponibile su CodePlex (naudio.codeplex.com). Seguendo i collegamenti da tale sito, è possibile estrarre blog del Mark imposizione per alcuni esempi di codice e sito esercitazioni del grigio Sebastian.
È possibile utilizzare la libreria NAudio in Windows Form o applicazioni WPF. Poiché le funzioni del Win32 API accede tramite PInvoke, non è possibile utilizzare con Silverlight.
Per questo articolo, ho utilizzato NAudio versione 1.3.8. Quando si crea un progetto che utilizza NAudio, sarà necessario compilare per l'elaborazione a 32 bit. Passare alla scheda Genera della pagina delle proprietà e selezionare x 86 dalla casella di riepilogo a discesa piattaforma di destinazione.
Sebbene la libreria fornisce numerose funzionalità per applicazioni specializzate che è necessario utilizzare suono, intendo mostrare una tecnica che potrebbe essere relativo in un'applicazione più generica.
Si supponga, ad esempio, l'applicazione consente di trascinare gli oggetti della finestra e si desidera questo trascinando per essere accompagnato da un segnale acustico semplice (un seno wave, ad esempio) che aumenta in frequenza più Ottiene l'oggetto dal centro della finestra.
Si tratta di un processo per audio Wave.
Quasi tutti i PC questi giorni includono suono generazione hardware, spesso implementato con un chip o due a destra sulla scheda madre. Questo componente hardware non è in genere molto più di una coppia di convertitori da digitale ad analogico (DACs). Fornire un flusso costante di valori interi che descrive un waveform per due DACs e audio stereo proviene.
La quantità di dati è coinvolto? Le applicazioni comunemente questi giorni generare “ ” di qualità CD audio. La frequenza di campionamento è una costante 44,100 campionamenti al secondo. (Teorema Nyquist indica che la frequenza di campionamento deve essere almeno due volte la frequenza più alta per essere riprodotto. Esseri umani sono comunemente detto sentire i suoni con frequenze tra 20 Hz e 20, 000 Hz, in modo che sia adeguato comodamente 44,100.) Ciascun esempio è un integer a 16 bit con segno, una dimensione che implica un rapporto segnale / rumore di decibel 96.
Rendendo onde
L'API Win32 fornisce l'accesso all'hardware di generazione suono mediante un insieme di funzioni a partire da waveOut parole. La libreria NAudio incapsula tali funzioni in una classe WaveUscita che si occupa di interoperabilità Win32 e nasconde la maggior parte delle oltre il messiness.
WaveUscita richiede una classe fornita che implementa l'interfaccia IWaveProvider, che significa che la classe definisce una proprietà di tipo WaveFormat che (almeno) indica la frequenza di campionamento e il numero di canali gettable. La classe definisce inoltre un metodo denominato lettura. Gli argomenti per il metodo Read includono un buffer di matrice di byte che la classe è necessaria riempire con dati Wave. Con le impostazioni predefinite, leggere da questo metodo verrà chiamato 10 volte al secondo. Rientrano in questo buffer riempito recupero un po' e si sentirà unaesthetic spazi vuoti in static audio e fastidioso.
NAudio fornisce un paio di classi astratte che implementano IWaveProvider e semplificare le cose un po' per processi audio comuni. La classe WaveProvider16 implementa un metodo astratto di lettura che consente di riempire il buffer con shorts anziché byte, pertanto si Don ’t necessario interrompere gli esempi nella metà.
Nella figura 1 viene illustrata una classe SineWaveOscillator semplice che deriva da WaveProvider16. Il costruttore consente di specificare una frequenza di campionamento ma chiama il costruttore della classe base con un secondo argomento che indica un canale per suoni monofonico.
Figura 1 Una classe per generare seno Wave esempi per NAudio
class SineWaveOscillator : WaveProvider16 {
double phaseAngle;
public SineWaveOscillator(int sampleRate):
base(sampleRate, 1) {
}
public double Frequency { set; get; }
public short Amplitude { set; get; }
public override int Read(short[] buffer, int offset,
int sampleCount) {
for (int index = 0; index < sampleCount; index++) {
buffer[offset + index] =
(short)(Amplitude * Math.Sin(phaseAngle));
phaseAngle +=
2 * Math.PI * Frequency / WaveFormat.SampleRate;
if (phaseAngle > 2 * Math.PI)
phaseAngle -= 2 * Math.PI;
}
return sampleCount;
}
}
SineWaveOscillator definisce due proprietà denominate frequenza (di tipo double) e ampiezza (un breve). Il programma gestisce un campo denominato phaseAngle sempre compreso tra 0 e 2π. Per ogni campione di phaseAngle è passato alla funzione Math.sin e quindi incrementato di un valore denominato l'incremento di angolo fase, che è un semplice calcolo riguardanti la frequenza e la frequenza di campionamento.
(Se si prevede essere generazione molte forme d'onda contemporaneamente, sarà necessario ottimizzare la velocità di elaborazione utilizzando integer aritmetica quando possibile, anche per la portata dell'implementazione di una tabella wave seno come una matrice di shorts. Ma di semplice utilizzo dell'audio Wave, calcoli punto mobile sono corretti).
Per utilizzare SineWaveOscillator in un programma, è necessario un riferimento alla libreria NAudio.dll e l'utilizzo di una direttiva:
using NAudio.Wave;
Ecco il codice che avvia la riproduzione di un suono.
WaveOut waveOut = new WaveOut();
SineWaveOscillator osc = new SineWaveOscillator(44100);
osc.Frequency = 440;
osc.Amplitude = 8192;
waveOut.Init(osc);
waveOut.Play();
Di seguito la proprietà frequenza viene inizializzata a 440 Hz. In musicali cerchi, che è A sopra C al centro e viene spesso utilizzato come standard a passo e per scopi di ottimizzazione. Naturalmente, come il suono viene riprodotto, è possibile modificare la proprietà frequenza. Per disattivare il suono, è possibile impostare l'ampiezza su 0, ma il SineWaveOscillator continuerà a ricevere le chiamate al metodo Play. Per interrompere le chiamate, chiamare Stop dell'oggetto WaveUscita. Quando non è più oggetto WaveUscita, è necessario chiamare il metodo Dispose su di esso per rilasciare correttamente le risorse.
Fuori chiave
Quando si utilizza SineWaveOscillator nel mio programma di esempio, non ho voluto. Volevo un suono per accompagnare oggetti trascinati all'interno della finestra e desideravo la frequenza di tale suono sia basata sulla distanza dell'oggetto dal centro. Ma come è stato spostato gli oggetti, le transizioni di frequenza non sono uniformi. Era ottenere una glissando scuro (ad esempio tra le chiavi di un piano o di un harp le stringhe è curvato dita), mentre ho voluto era un portamento uniforme (come un trombone o clarinet apertura di “ Rhapsody in blu di Gershwin ”).
Il problema è che ogni chiamata di Ascolta metodo da WaveUscita causa un intero buffer da riempire basata sulla stessa value di frequenza. Durante il tempo che il metodo Play riempie il buffer, la frequenza non possibile modificare quando l'utente trascina il mouse perché Play è in esecuzione sul thread dell'interfaccia utente.
In che modo errato è il problema, e le dimensioni questi buffer?
La classe WaveUscita in NAudio include una proprietà DesiredLatency che, per impostazione predefinita, viene impostata su 300 millisecondi. Include inoltre una proprietà NumberOfBuffers impostata su 3. (Più buffer Guida throughput poiché l'API può leggere un buffer mentre un'applicazione riempie un'altra). Di conseguenza, ogni buffer equivale a.1 secondo degli esempi. Tramite esperimenti, ho scoperto che non è possibile ridurre significativamente il DesiredLatency senza provocare interruzioni audible. È possibile aumentare il numero di buffer, assicurarsi di selezionare un valore in modo che la dimensione del buffer in byte è un multiplo di 4, ma questa non sembra contribuire in modo significativo. È inoltre possibile fare in modo che il metodo Play eseguito in un thread secondario, passando al costruttore WaveUscita la chiamata al metodo statico WaveCallbackInfo.FunctionCallback, ma che non consentono più uno.
È presto diventato evidente che avevo bisogno era un'oscillator che portamento la stessa eseguita durante la compilazione del buffer. Invece di SineWaveOscillator, è stato necessario un PortamentoSineWaveOscillator.
PortamentoSineWaveOscillator
Volevo effettuare anche altre modifiche. Percezione umana della frequenza è logaritmica. Il octave è definita come un raddoppiando della frequenza e octaves sono chiaramente simili attraverso la gamma. Il sistema nervous risorse umane, la differenza tra Hz 100 e 200 Hz è lo stesso la differenza tra 1000Hz e 2000Hz. In musica, ogni octave comprende 12 passaggi chiaramente uguali chiamati semitones. Di conseguenza, le frequenze di questi semitones aumentare in modo sequenziale in base a un fattore di moltiplicazione uguale al dodicesima principale di due.
Volevo mio portamento essere logaritmiche, in modo che in PortamentoSineWaveOscillator ho definito una nuova proprietà denominata passo calcola la frequenza simile al seguente:
Frequency = 440 * Math.Pow(2, (Pitch - 69) / 12)
Si tratta di una formula standard piuttosto che provengono da convenzioni utilizzate nel MIDI Musical Instrument Digital Interface (), che verrà illustrato in un futuro articolo. Se il numero di tutte le note del piano dal basso verso l'alto in cui medio C viene assegnato un valore di passo di 60 quindi A sopra medio C è 69 e la formula determina la frequenza di 440 Hz. In MIDI questi valori passo sono numeri interi, ma nella classe PortamentoSineWaveOscillator passo è un valore double gradazioni tra le note sono possibili.
In PortamentoSineWaveOscillator, Play metodo rileva quando passo è stato modificato e quindi modifica gradualmente il valore utilizzato per calcolare la frequenza (e pertanto l'angolo fase incrementare) in base alle dimensioni del buffer rimanente. La logica consente di modificare durante l'esecuzione del metodo, ma che verrà effettuata solo se è in esecuzione su un thread secondario Play passo.
Come programma AudibleDragging nel download di codice riportato di seguito, funzionava! Il programma crea blocchi poco sette diversi colori in prossimità del centro della finestra. Quando li afferrare con il mouse, il programma crea un oggetto WaveUscita utilizzando PortamentoSineWaveOscillator. Come l'oggetto viene trascinato, il programma semplicemente determina una distanza dal centro della finestra e imposta il tono della oscillator basato sulla formula seguente:
60 + 12 * distance / 200;
In altre parole, C medio più uno octave per ogni 200 unità distanza. Naturalmente, AudibleDragging è un piccolo programma sembrerà e potrebbe indurre è più che mai le applicazioni devono sempre essere invisibile all'utente. Ma la possibilità di generare segnali acustici personalizzati in fase di esecuzione è semplicemente troppo potente rifiutato categorically.
Riprodurre in
Naturalmente, non si è limitati a oscillators wave seno singolo. È anche possibile derivare un mixer da WaveProvider16 e che consente di combinare oscillators diversi. È possibile combinare forme d'onda semplice in quelli più complessi. L'utilizzo di una proprietà passo viene suggerito un approccio semplice a specificare note musicali.
Ma se si tratta di strumenti musicali che si desidera che l'applicazione blast dagli altoparlanti e musica, si sarà lieti di sapere che NAudio include anche le classi che consentono di generare messaggi MIDI dalle applicazioni Windows Form o WPF. Viene illustrato come effettuare questa operazione al più presto.
Charles Petzold è consulente redattore esperti di MSDN Magazine*.* Il suo libro più recente è “ il Turing Annotated: Una presentazione tramite carta storici di Alan Turing Computability e Machine Turing guidata ” (Wiley, 2008). Petzold blog sul suo sito Web charlespetzold.com.
Grazie all'esperto tecnica seguente per la revisione di questo articolo: Mark Heath