Giugno 2019

Volume 34 Numero 6

Il presente articolo è stato tradotto automaticamente.

[Voce]

Sintesi vocale in .NET

Dal Smirnov per per | Giugno 2019

Spesso volano a Finlandia per visualizzare il mom. Ogni volta che il piano viene inserita in aeroporto Vantaa, mi sorpresi dalla rapidità con head passeggeri come un numero ridotto per l'aeroporto di uscire. Il set di maggior off per la connessione di voli in destinazioni che si estende su tutti centrali ed Europa orientale. È non sorprende, quindi, quando il piano di inizia il descent, ha un numero molto elevato di annunci sui voli. "Se la destinazione è Tallinn, cercare gate 123," "Per volo XYZ a Saint Pietroburgo, procedere al cancello 234" e così via. Naturalmente, gli operatori automatici dei voli non parlo in genere dodici lingue, in modo che usino inglese, che non è il linguaggio nativo di passeggeri la maggior parte. Prendere in considerazione la qualità dell'annuncio pubblico (PA) sistemi nell'airliners, più il rumore di motore, gettare la spugna simpatici e altri disturbi, come possono tutte le informazioni in modo efficace trasmesse?

Beh, ogni postazione è dotato di cuffie. Molti, se non tutti i piani interurbane singole schermate attualmente dispongono (e quelli locali hanno almeno diversi canali audio). Cosa accade se un passeggero potrebbe scegliere la lingua per gli annunci e un sistema di eseguire l'onboarding di computer consentiti gli operatori automatici dei voli creare e dynamic send (che non è, pre-registrati) di messaggi vocali? In questo caso il problema principale è la natura dinamica dei messaggi. È facile per pre-registrare istruzioni relative alla sicurezza, ristorazione opzioni e così via, perché saranno raramente aggiornati. Ma è necessario creare messaggi letteralmente in tempo reale.

Fortunatamente, è una tecnologia avanzata che consente di: sintesi sintesi vocale (TTS). Tali sistemi è possibile notare raramente, ma sono molto diffusione: pubblici annunci e messaggi di richiesta in call center, i dispositivi di navigazione, giochi, dispositivi Smart Device e altre applicazioni sono tutti gli esempi in cui prompt registrati precedentemente non è sufficiente o con una forma d'onda digitalizzata è infatti assolutamente vietata a causa delle limitazioni di memoria (un testo letto da un motore di sintesi vocale è nettamente inferiore per archiviare una forma d'onda digitalizzata).

Sintesi vocale basata sul computer è stato introdotto difficilmente. Le società di telecomunicazioni investito in sintesi vocale per superare le limitazioni di messaggi pre-registrati e ricercatori militari avere provato a messaggi vocali e gli avvisi per semplificare le interfacce di controllo complessa. Sintetizzatori portabili sono stati sviluppati in modo analogo per le persone affette da disabilità. Per avere un'idea di ciò che tali dispositivi sono stati in grado di 25 anni fa, restare in attesa per la traccia "Comunicazione continua" in album Floyd rosa 1994 "la divisione a forma di campana," scheda di rete di Stephen afferma in cui il suo famoso riga: "Dobbiamo fare è sufficiente Assicurarsi che abbiamo continuiamo parlando."

API sintesi vocale vengono spesso fornite insieme a loro "opposta", ovvero il riconoscimento vocale. Anche se sono necessari entrambi per l'interazione uomo-computer effettivo, l'esplorazione è incentrato specificamente sulla sintesi vocale. Userà l'API sintesi vocale di Microsoft .NET per creare un prototipo di un sistema PA airliner. Si esamineranno anche in background, per comprendere le nozioni di base dell'approccio "selezione delle unità" per sintesi vocale. E mentre sarà illustrando la costruzione di un'applicazione desktop, in questo caso i principi si applicano direttamente alle soluzioni basate sul cloud.

Implementare il proprio sistema di riconoscimento vocale

Prima del sistema di annunci in corso la creazione di prototipi, è possibile esplorare l'API con un semplice programma. Avviare Visual Studio e creare un'applicazione console. Aggiungere un riferimento a System. Speech e implementare il metodo in figura 1.

Figura 1 System.Speech.Synthesis metodo

using System.Speech.Synthesis;
namespace KeepTalking
{
  class Program
  {
    static void Main(string[] args)
    {
      var synthesizer = new SpeechSynthesizer();
      synthesizer.SetOutputToDefaultAudioDevice();
      synthesizer.Speak("All we need to do is to make sure we keep talking");
    }
  }
}

A questo punto compilare ed eseguire. Solo poche righe di codice e aver replicato la frase Hawking famosa.

Quando si stesse digitando questo codice, IntelliSense aperta una finestra con tutte le proprietà della classe SpeechSynthesizer e metodi pubblici. Se l'hai persa, usare "Spazio di controllo" o "dot" tasto di scelta rapida (o esaminare bit.ly/2PCWpat). Novità interessano in questo caso?

In primo luogo, è possibile impostare destinazioni di output diversi. Può trattarsi di un file audio o un flusso o persino null. In secondo luogo, si dispone sia sincrona (come nell'esempio precedente) e output asincrono. È inoltre possibile regolare il volume e il tasso di riconoscimento vocale, sospendere e riprenderne l'esecuzione e ricevere eventi. È anche possibile selezionare le voci. Questa funzionalità è importante in questo caso, perché verrà usato per generare l'output in lingue diverse. Ma le voci sono disponibili? Scopriamolo insieme, utilizzando il codice nel figura 2.

Figura 2 vocale informazioni codice

using System;
using System.Speech.Synthesis;
namespace KeepTalking
{
  class Program
  {
    static void Main(string[] args)
    {
      var synthesizer = new SpeechSynthesizer();
      foreach (var voice in synthesizer.GetInstalledVoices())
      {
        var info = voice.VoiceInfo;
        Console.WriteLine($"Id: {info.Id} | Name: {info.Name} |
          Age: {info.Age} | Gender: {info.Gender} | Culture: {info.Culture}");
      }
      Console.ReadKey();
    }
  }
}

Nel mio computer con Windows 10 Home l'output risultante dal figura 2 è:

Id: TTS_MS_EN-US_DAVID_11.0 | Name: Microsoft David Desktop |
  Age: Adult | Gender: Male | Culture: en-US
Id: TTS_MS_EN-US_ZIRA_11.0 | Name: Microsoft Zira Desktop |
  Age: Adult | Gender: Female | Culture: en-US

Sono disponibili solo due voices in lingua inglese e per quanto riguarda altri linguaggi? Beh, ogni voce richiede spazio su disco, in modo che non sono installati per impostazione predefinita. Per aggiungerle, passare a Start | Le impostazioni | Ora e lingua | Area e lingua e fare clic su Aggiungi una lingua, assicurandosi di selezionare vocale nelle funzionalità facoltative. Anche se Windows supporta più di 100 lingue, solo circa 50 supportano sintesi vocale. È possibile esaminare l'elenco delle lingue supportate nella bit.ly/2UNNvba.

Dopo il riavvio del computer, un nuovo language pack deve essere disponibile. Nel mio caso, dopo aver aggiunto il russo, ho una nuova voce installata:

Id: TTS_MS_RU-RU_IRINA_11.0 | Name: Microsoft Irina Desktop |
  Age: Adult | Gender: Female | Culture: ru-RU

È ora possibile tornare al primo programma e aggiungere queste due righe anziché al sintetizzatore. Pronunciare chiamata:

synthesizer.SelectVoice("Microsoft Irina Desktop");
synthesizer.Speak("Всё, что нам нужно сделать, это продолжать говорить");

Se si desidera passare tra i linguaggi, è possibile inserire chiamate di SelectVoice qua e là. Ma un modo migliore consiste nell'aggiungere una struttura al riconoscimento vocale. A tal fine, è possibile usare la classe PromptBuilder, come illustrato nella figura 3.

Figura 3 classe PromptBuilder

using System.Globalization;
using System.Speech.Synthesis;
namespace KeepTalking
{
  class Program
  {
    static void Main(string[] args)
    {
      var synthesizer = new SpeechSynthesizer();
      synthesizer.SetOutputToDefaultAudioDevice();
      var builder = new PromptBuilder();
      builder.StartVoice(new CultureInfo("en-US"));
      builder.AppendText("All we need to do is to keep talking.");
      builder.EndVoice();
      builder.StartVoice(new CultureInfo("ru-RU"));
      builder.AppendText("Всё, что нам нужно сделать, это продолжать говорить");
      builder.EndVoice();
      synthesizer.Speak(builder);
    }
  }
}

Si noti che è necessario chiamare EndVoice, in caso contrario, si otterrà un errore di runtime. Inoltre, ho utilizzato CultureInfo come un altro modo per specificare una lingua. PromptBuilder dispone di molti metodi utili, ma si desidera attirare l'attenzione su AppendTextWithHint. Provare questo codice:

var builder = new PromptBuilder();
builder.AppendTextWithHint("3rd", SayAs.NumberOrdinal);
builder.AppendBreak();
builder.AppendTextWithHint("3rd", SayAs.NumberCardinal);
synthesizer.Speak(builder);

Un altro modo strutturare l'input e specificare la modalità di lettura consiste nell'usare sintesi della voce Markup Language (SSML), che è una raccomandazione multipiattaforma sviluppata per il gruppo di lavoro Browser Voice internazionale (w3.org/TR/speech-synthesis). Motori di TTS Microsoft forniscono un supporto completo per SSML. Ciò viene illustrato come utilizzarla:

string phrase = @"<speak version=""1.0""
  http://www.w3.org/2001/10/synthesis""
  xml:lang=""en-US"">";
phrase += @"<say-as interpret-as=""ordinal"">3rd</say-as>";
phrase += @"<break time=""1s""/>";
phrase += @"<say-as interpret-as=""cardinal"">3rd</say-as>";
phrase += @"</speak>";
synthesizer.SpeakSsml(phrase);

Si noti che impiega una chiamata diversa nella classe SpeechSynthesizer.

È ora possibile lavorare su prototipo. Questa volta crea un nuovo progetto Windows Presentation Foundation (WPF). Aggiungere un modulo e un paio di pulsanti per le richieste in due diverse lingue. Aggiungere quindi fare clic su gestori, come illustrato nella finestra di XAML in figura 4.

Figura 4 il codice XAML

using System.Collections.Generic;
using System.Globalization;
using System.Speech.Synthesis;
using System.Windows;
namespace GuiTTS
{
  public partial class MainWindow : Window
  {
    private const string en = "en-US";
    private const string ru = "ru-RU";
    private readonly IDictionary<string, string> _messagesByCulture =
      new Dictionary<string, string>();
    public MainWindow()
    {
      InitializeComponent();
      PopulateMessages();
    }
    private void PromptInEnglish(object sender, RoutedEventArgs e)
    {
      DoPrompt(en);
    }
    private void PromptInRussian(object sender, RoutedEventArgs e)
    {
      DoPrompt(ru);
    }
    private void DoPrompt(string culture)
    {
      var synthesizer = new SpeechSynthesizer();
      synthesizer.SetOutputToDefaultAudioDevice();
      var builder = new PromptBuilder();
      builder.StartVoice(new CultureInfo(culture));
      builder.AppendText(_messagesByCulture[culture]);
      builder.EndVoice();
      synthesizer.Speak(builder);
    }
    private void PopulateMessages()
    {
      _messagesByCulture[en] = "For the connection flight 123 to
        Saint Petersburg, please, proceed to gate A1";
      _messagesByCulture[ru] =
        "Для пересадки на рейс 123 в  Санкт-Петербург, пожалуйста, пройдите к выходу A1";
    }
  }
}

Ovviamente, si tratta di un prototipo di piccole dimensioni. In uno scenario reale, PopulateMessages probabilmente letti da una risorsa esterna. Ad esempio, un supervisore dei voli possibile generare un file con i messaggi in più lingue utilizzando un'applicazione che chiama un servizio, ad esempio Bing Translator (bing.com/translator). Il modulo sarà molto più sofisticati e generato in modo dinamico basato sulle lingue disponibili. Sarà presente la gestione degli errori e così via. Ma il concetto consiste nell'illustrare le funzionalità di base.

Decostruzione di riconoscimento vocale

Finora abbiamo ottenuto risultati il nostro obiettivo con un piccolo sorprendentemente codebase. Diamo un'opportunità per analizzare in dettaglio e capire meglio come TTS motori di lavoro.

Esistono molti approcci per la costruzione di un sistema di sintesi vocale. In passato, i ricercatori sono tentato di individuare un set di regole di pronuncia su cui basare gli algoritmi. Se è stato studiato mai una lingua straniera, si ha familiarità con le regole, ad esempio "lettera"c"precede la 'e', 'i', 'y' verrà pronunciato quello di ' come 'city', ma prima di 'a', 'o,' 'u' come 'k' come in"gatto"." Che si verifichi sono presenti così tante le eccezioni e casi speciali, come le modifiche di pronuncia in parole consecutive, che è difficile costruzione di un set completo di regole. Inoltre, la maggior parte dei sistemi di questo tipo tendono a produrre una voce "computer" distinte, ovvero imagine principianti in una lingua straniera pronunciati una parola lettera per lettera.

Per maggiore naturalezza una voce al riconoscimento vocale, research ha spostato verso sistemi basati su database di grandi dimensioni di frammenti di riconoscimento vocale registrati e questi motori ora dominano il mercato. Comunemente noto come selezione delle unità concatenazione sintesi vocale, questi motori selezionare gli esempi di riconoscimento vocale (unità) in base al testo di input e di concatenano in frasi. In genere, motori di usano l'elaborazione in due fasi molto simili compilatori: In primo luogo, analizzare l'input in una struttura interna di ad elenco o albero di trascrizione fonetica e metadati aggiuntivi e quindi sintetizzare suono basata su tale struttura.

Poiché stiamo affrontando linguaggi naturali, parser sono più sofisticati rispetto a per linguaggi di programmazione. Quindi, di là della Tokenizzazione (trovare i limiti delle parole e frasi), parser devono correggere errori di digitazione, identificare parti del discorso, analizzare segni di punteggiatura e decodificare abbreviazioni, forme contratte e simboli speciali. Output del parser è in genere diviso da frasi o le frasi e formato in raccolte che descrive le parole tale gruppo e trasportare i metadati come parti del discorso, pronuncia, stress e così via.

I parser sono responsabili per la risoluzione di ambiguità nell'input. Che cos'è, ad esempio, "Ripristino di emergenza."? Si tratta di "medici" come "ripristino di emergenza. Smith"o"unità"come"Unità Privet?" Ed è una frase "Dr" perché inizia con una lettera maiuscola e termina con un punto? È "progetto" un verbo o un sostantivo? Questo è importante sapere perché quando viene usata sia su sillabe diversi.

Queste domande non sono sempre facili da rispondere e molti sistemi di sintesi vocale hanno parser separati per i domini specifici: caratteri numerici, date, abbreviazioni, gli acronimi, nomi geografici, forme particolari di testo, ad esempio URL e così via. Poiché sono specifiche del linguaggio e area. Per fortuna, tali problemi sono stati studiati per molto tempo e sono disponibili Framework ben sviluppato e librerie per fare affidamento sulle.

Il passaggio successivo è la generazione di forme di pronuncia, ad esempio l'assegnazione di tag di struttura ad albero con simboli audio (ad esempio la trasformazione "school" in "k s Oh l"). Questa operazione viene eseguita dagli algoritmi di grafemi-a-fonema speciali. Per le lingue, ad esempio spagnolo, alcune regole relativamente semplice possono essere applicate. Ma per altri utenti, ad esempio inglese, pronuncia presenta differenze in modo significativo la forma scritta. Metodi statistici vengono quindi usati insieme ai database per le parole noti. Successivamente, è necessaria un'ulteriore elaborazione post-lessicale, perché la pronuncia delle parole può essere modificato quando combinati in una frase.

Sebbene i parser tenta di estrarre tutte le informazioni possibili dal testo, c'è qualcosa che pertanto elusiva che non sia estraibile: prosodia o intonazione. Durante la pronuncia, utilizziamo prosodia per evidenziare alcune parole, per trasmettere le emozioni e per indicare a domande, i comandi e le frasi affermativa. Ma testo scritto non dispone di simboli per indicare di prosodia. Certo, segni di punteggiatura offre alcuni contesto: Una virgola significa passare qualche, mentre un punto indica uno più esteso, e un punto interrogativo che si aumenta l'intonazione verso la fine di una frase. Ma se mai letto i bambini una storia bedtime, si sa di quanto queste regole sono dalla lettura reale.

Inoltre, due utenti diversi spesso leggono lo stesso testo in modo diverso (porre i bambini che è preferibile alla storie bedtime di lettura, sia il coniuge/partner). Per questo motivo non è possibile utilizzare in modo affidabile metodi statistici poiché esperti diversi produrrà etichette diverse per l'apprendimento sorvegliato. Questo problema è complessa e, nonostante la ricerca con utilizzo intensivo, tutt'altro che da risolvere. I programmatori migliori possono eseguire è usare l'elemento, che dispone di un tag di prosodia SSML.

Reti neurali in sintesi vocale

Statistiche o metodi di apprendimento per anni applicati in tutte le fasi di elaborazione di sintesi vocale. Ad esempio, i modelli Markov nascosto vengono utilizzati per creare i parser che produce l'analisi più probabile o per eseguire l'assegnazione di etichette per i database di esempio di riconoscimento vocale. Gli alberi delle decisioni vengono utilizzati nella selezione delle unità o negli algoritmi di grafemi-a-fonemi, mentre le reti neurali e deep learning sono emersi nei dispositivi perimetrali sbavature di ricerca di sintesi vocale.

È possibile considerare un campione audio come una serie temporale di campionamento della forma d'onda. Tramite la creazione di un modello Autoregressivo, è possibile prevedere nell'esempio successivo. Di conseguenza, il modello genera il bubbling tipo di riconoscimento vocale, come un bambino di apprendimento comunicare con da imitazione suoni. Abbiamo condizione ulteriormente questo modello nella trascrizione audio o l'output pre-elaborazione di un sistema di sintesi vocale esistente, si ottiene un modello di riconoscimento vocale con parametri. L'output del modello descrive un spectrogram per un vocoder producendo forme d'onda effettive. Poiché questo processo non si basa su un database con campioni registrati, ma è propria, il modello prevede un footprint di memoria di piccole dimensioni e consente la regolazione dei parametri.

Il training del modello su naturale, l'output conserva quindi tutte le relative caratteristiche, tra cui sperimentare, sollecitazioni e intonazione (in modo che le reti neurali potenzialmente possono risolvere il problema di prosodia). È possibile anche regolare il tono, creare una voce di completamente diversa e persino riprodurre firma dei.

Al momento della stesura di questo articolo, Microsoft offre la versione di anteprima di una rete neurale sintesi vocale (bit.ly/2PAYXWN). Fornisce quattro voci con elevata qualità e quasi istantanee sulle prestazioni.

Generazione del riconoscimento vocale

Ora che abbiamo la struttura ad albero con i metadati, attiviamo alla generazione del riconoscimento vocale. Sistemi di sintesi vocale originale ha tentato di sintesi segnali combinando sinusoids. Un altro approccio interessante è stata la creazione di un sistema di equazioni differenziali che descrive il compri una voce umana come tubi connesse diverse di diametri diversi e lunghezze. Tali soluzioni sono molto compatte, ma purtroppo sembrare piuttosto meccaniche. Pertanto, come accade con sintetizzatori musicali, lo stato attivo vengono spostati gradualmente a soluzioni basate su esempi, che richiedono spazio significativo, ma essenzialmente un tono naturale.

Per compilare un sistema di questo tipo, è necessario disporre di molte ore di registrazioni di alta qualità di un attore professionale legge testo costruito appositamente. Questo testo viene suddiviso in unità, con l'etichetta e archiviato in un database. Generazione del riconoscimento vocale diventa un'attività di selezione unità appropriata e li mettono insieme.

Poiché non si esegue la sintesi vocale, è possibile modificare in modo significativo i parametri in fase di esecuzione. Se serve sia maschi e femmine voices o necessario fornire le evidenziazioni a livello di area (ad esempio, Gaelico o irlandese), dovranno essere registrato separatamente. Il testo deve essere costruito per coprire tutte le unità di suono possibili, che è necessario. E gli attori devono leggere un tono neutra per rendere più semplice la concatenazione.

La divisione e assegnazione di etichette sono anche altre attività non semplice. Utilizzato deve essere eseguita manualmente, accettando settimane noiosa. Per fortuna, apprendimento automatico ora viene applicato a questo.

Dimensioni dell'unità sono probabilmente il parametro più importante per un sistema di sintesi vocale. Ovviamente, usando frasi intere, possiamo rendere i suoni più naturali anche con prosodia corretto, ma la registrazione e l'archiviazione che è impossibile la quantità di dati. Possiamo è dividerlo in parole? Probabilmente, ma quanto tempo impiegherà un attore malintenzionato leggere un dizionario intero? Con le limitazioni relative alle dimensioni del database è rivolta? Su altro lato, è possibile registrare solo alfabeto, che è sufficiente solo per un concorso bee ortografia. Quindi, in genere le unità sono selezionate come due gruppi di tre lettere. Non sono necessariamente sillabe, come i gruppi di spanning bordi sillaba possono essere incollati molto meglio.

A questo punto l'ultimo passaggio. Presenza di un database di unità di riconoscimento vocale, è necessario affrontare la concatenazione. Che si verifichi, indipendentemente dal modo neutro di intonazione era nella registrazione originale, ci si connette unità richiede comunque rettifiche per evitare passa nella fase, frequenza e volume. Questa operazione viene eseguita con (DSP) di elaborazione dei segnali digitali. Può essere utilizzato anche per aggiungere alcuni intonazione di frasi, come aumentare o diminuire la voce generata per le asserzioni o domande.

Conclusioni

In questo articolo trattato solo l'API .NET. Altre piattaforme offrono funzionalità simili. La maggior parte delle distribuzioni di Linux includono il motore eSpeak MacOS ha NSSpeechSynthesizer in Cocoa con funzionalità simili. Tutte queste API sono accessibili tramite il codice nativo, pertanto è necessario usare C# o C++ o Swift. Per lo sviluppo multipiattaforma ecosistemi come Python, esistono alcuni Bridge, ad esempio Pyttsx, ma in genere presentano determinate limitazioni.

I fornitori cloud, d'altra parte, pubblico a livello di destinazione e offrono servizi per linguaggi e piattaforme più diffusi. Anche se la funzionalità è paragonabile tra i fornitori, supporto per i tag SSML possono variare, controllare la documentazione prima di scegliere una soluzione.

Microsoft offre un servizio di sintesi vocale come parte di servizi cognitivi (bit.ly/2XWorku). Non solo offre 75 voices in 45 lingue, ma consente inoltre di creare il proprio voci. A tal fine, il servizio deve file audio con una trascrizione corrispondente. È possibile scrivere prima di tutto il testo desiderato, quindi fare in modo di leggerlo, o eseguire una registrazione esistente e scrivere la trascrizione. Dopo aver caricato i set di dati in Azure, un algoritmo esegue il training di apprendimento un modello per il proprio univoco "voice font." Un ottimo manuale dettagliato reperibili bit.ly/2VE8th4.

Un modo pratico per accedere ai servizi cognitivi di riconoscimento vocale consiste nell'usare il riconoscimento vocale Software Development Kit (bit.ly/2DDTh9I). Supporta il riconoscimento vocale e sintesi vocale e disponibile per tutti i linguaggi più diffusi e le principali piattaforme mobili e desktop. Si è ben documentato e sono disponibili numerosi esempi di codice su GitHub.

Sintesi vocale continua a essere di aiuto notevole alle persone con particolari esigenze. Ad esempio, si consiglia di consultare linka.su, un sito Web creato da un programmatore talento con paralisi cerebrali consentono agli utenti con sintesi vocale e musculoskeletal autoimmuni, autism o quelle il ripristino da un tratto. Conoscendo esperienza personale le limitazioni che riscontrano, l'autore ha creato una gamma di applicazioni per le persone che non è possibile digitare su una tastiera standard, possono selezionare solo una lettera alla volta o sufficiente toccare un'immagine su un tablet. Grazie a sintesi vocale, lancia letteralmente una voce a coloro che non è disponibile. Vuole che abbiamo tutti, come i programmatori, potrebbe essere utili ad altri utenti.


Smirnov per Iliaha più di 20 anni di esperienza nello sviluppo di applicazioni aziendali su piattaforme principali, principalmente in Java e .NET. Per l'ultimo decennio, egli è specializzato nella simulazione dei rischi finanziari. Conseguito tre master Repubblica gradi, FRM e altri professionisti certificazioni.

Grazie al seguente esperto tecnico Microsoft per la revisione dell'articolo: Sheng Zhao (Sheng.Zhao@microsoft.com)
Sheng Zhao è principal di gruppo ingegneria del software con contenuto vocale STCA nel Beijing (Pechino)


Discutere di questo articolo nel forum di MSDN Magazine