{"id":2032,"date":"2016-03-23T09:49:07","date_gmt":"2016-03-23T08:49:07","guid":{"rendered":"https:\/\/sii.pl\/blog\/?p=2032"},"modified":"2023-08-14T15:51:53","modified_gmt":"2023-08-14T13:51:53","slug":"naudio-biblioteka-do-obslugi-audio-w-net-cz-2","status":"publish","type":"post","link":"https:\/\/sii.pl\/blog\/naudio-biblioteka-do-obslugi-audio-w-net-cz-2\/","title":{"rendered":"NAudio &#8211; biblioteka do obs\u0142ugi audio w .NET cz. 2"},"content":{"rendered":"\n<p>W poprzednim artykule om\u00f3wi\u0142em podstawowe funkcje biblioteki NAudio. Przedstawi\u0142em w jaki spos\u00f3b odczytywa\u0107 pliki audio i je odtwarza\u0107. Dzisiaj zajmiemy si\u0119 innymi przydatnymi funkcjami jakie udost\u0119pnia nam biblioteka.<\/p>\n\n\n\n<p>Jedn\u0105 z bardzo przydatnych funkcji jest konwersja format\u00f3w. B\u0119dzie to konwersja do formatu WAV. Do tego celu u\u017cywamy klasy WaveFormatConversionStream. Klasa ta udost\u0119pnia nam jeden konstruktor.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\npublic WaveFormatConversionStream(WaveFormat targetFormat, WaveStream sourceStream);\n<\/pre><\/div>\n\n\n<p>Pierwszy parametr opisuje format docelowego pliku WAV, a drugi stanowi strumie\u0144 \u017ar\u00f3d\u0142owych danych.<\/p>\n\n\n\n<p>Klasa WaveFormat zawiera konstruktor, kt\u00f3ry przyjmuje trzy parametry:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>cz\u0119stotliwo\u015b\u0107 pr\u00f3bkowania<\/li>\n\n\n\n<li>rozdzielczo\u015b\u0107 bitowa<\/li>\n\n\n\n<li>ilo\u015b\u0107 kana\u0142\u00f3w<\/li>\n<\/ul>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\npublic WaveFormat(int rate, int bits, int channels);\n<\/pre><\/div>\n\n\n<p>Gdy ju\u017c mamy zdefiniowany obiekt klasy WaveFormatConversionStream, mo\u017cemy przyst\u0105pi\u0107 do samej konwersji. Do zapisu danych ze strumienia audio do pliku WAV, u\u017cyjemy statycznej metody CreateWaveFile klasy WaveFileWriter.<\/p>\n\n\n\n<p>Funkcja konwertuj\u0105ca plik MP3 do WAV wygl\u0105da nast\u0119puj\u0105co:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nprivate void ConvertMp3File(string inFileName, string outFileName, int rate, int bits, int channels)\n{\n    using (Mp3FileReader reader = new Mp3FileReader(inFileName))\n    {\n        using (WaveFormatConversionStream wfcs = new WaveFormatConversionStream(new WaveFormat(rate, bits, channels), reader))\n        {\n            WaveFileWriter.CreateWaveFile(outFileName, wfcs);\n        }                                \n    }\n \n}\n<\/pre><\/div>\n\n\n<p>Kolejn\u0105 klas\u0105 wart\u0105 om\u00f3wienia jest klasa WaveMixerStream32. Umo\u017cliwia ona sumowanie (miksowanie) wielu strumieni audio. Klasa ta posiada dwa konstruktory &#8211; jeden bezparametrowy, oraz drugi w kt\u00f3rym przekazujemy kolekcj\u0119 strumieni audio oraz warto\u015b\u0107 bool okre\u015blaj\u0105c\u0105 czy strumie\u0144 ma si\u0119 zako\u0144czy\u0107 gdy dane ze wszystkich dodanych strumieni zostan\u0105 odczytane.<\/p>\n\n\n\n<p>Strumienie do obiektu klasy WaveMixerStream32 dodajemy za pomoc\u0105 metody AddInputStream. Nale\u017cy pami\u0119ta\u0107, \u017ce wszystkie strumienie musz\u0105 by\u0107 tego samego formatu audio, czyli cz\u0119stotliwo\u015b\u0107 pr\u00f3bkowania, rozdzielczo\u015b\u0107 bitowa i ilo\u015b\u0107 kana\u0142\u00f3w musz\u0105 by\u0107 w ka\u017cdym strumieniu takie same. Zagl\u0105daj\u0105c do \u017ar\u00f3de\u0142 biblioteki widzimy, \u017ce funkcja AddInputStream ustala format na podstawie pierwszego dodanego strumienia i nie pozwala na dodanie kolejnego strumienia o odmiennym formacie:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\npublic void AddInputStream(WaveStream waveStream)\n{\n    if (waveStream.WaveFormat.Encoding != WaveFormatEncoding.IeeeFloat)\n        throw new ArgumentException(\"Must be IEEE floating point\", \"waveStream\");\n    if (waveStream.WaveFormat.BitsPerSample != 32)\n        throw new ArgumentException(\"Only 32 bit audio currently supported\", \"waveStream\");\n \n    if (inputStreams.Count == 0)\n    {\n        \/\/ first one - set the format\n        int sampleRate = waveStream.WaveFormat.SampleRate;\n        int channels = waveStream.WaveFormat.Channels;\n        this.waveFormat = WaveFormat.CreateIeeeFloatWaveFormat(sampleRate, channels);\n    }\n    else\n    {\n        if (!waveStream.WaveFormat.Equals(waveFormat))\n            throw new ArgumentException(\"All incoming channels must have the same format\", \"waveStream\");\n    }\n \n    lock (inputsLock)\n    {\n        this.inputStreams.Add(waveStream);\n        this.length = Math.Max(this.length, waveStream.Length);\n        \/\/ get to the right point in this input file\n        waveStream.Position = Position;\n    }\n}\n<\/pre><\/div>\n\n\n<p>Poni\u017cej przyk\u0142ad zastosowania klasy WaveMixerStream32 do zmiksowania dw\u00f3ch plik\u00f3w audio (dowolnego formatu) do pliku wynikowego (WAV):<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nprivate void Mix2FilesTo1(string fileName1, string fileName2, string outputFile)\n{\n    using (NAudio.Wave.WaveMixerStream32 mixStream = new NAudio.Wave.WaveMixerStream32())\n    {\n        NAudio.Wave.AudioFileReader afr1 = new AudioFileReader(fileName1);\n        NAudio.Wave.AudioFileReader afr2 = new AudioFileReader(fileName2);\n        mixStream.AddInputStream(afr1);\n        mixStream.AddInputStream(afr2);\n        WaveFileWriter.CreateWaveFile(outputFile, mixStream);\n    }\n \n}\n<\/pre><\/div>\n\n\n<p>Nale\u017cy mie\u0107 na uwadze, \u017ce wywo\u0142anie metody Dispose() na obiekcie klasy WaveMixerStream32 spowoduje wywo\u0142anie metody Dispose() na wszystkich obiektach reprezentuj\u0105cych strumienie wej\u015bciowe.<\/p>\n\n\n\n<p>NAudio poprzez swoj\u0105 modu\u0142ow\u0105 budow\u0119 umo\u017cliwia r\u00f3wnie\u017c \u0142atwe implementowanie funkcjonalno\u015bci typu DSP. Tworz\u0105c klasy dziedzicz\u0105ce po klasie WaveStream i umieszczaj\u0105c algorytmy przetwarzaj\u0105ce w nadpisanej metodzie Read, mo\u017cemy implementowa\u0107 funkcje DSP. Razem z bibliotek\u0105 dostarczony jest doskona\u0142y przyk\u0142ad takiej funkcjonalno\u015bci w postaci klasy SimpleCompressorStream &#8211; jest to prosty kompresor dynamiki. Zagl\u0105daj\u0105c do \u017ar\u00f3de\u0142, widzimy w jaki spos\u00f3b realizowane jest przetwarzanie sygna\u0142u:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\npublic override int Read(byte&#x5B;] array, int offset, int count)\n{\n    lock (lockObject)\n    {\n        if (Enabled)\n        {\n            if (sourceBuffer == null || sourceBuffer.Length &lt; count)\n                sourceBuffer = new byte&amp;#91;count&amp;#93;;\n            int sourceBytesRead = sourceStream.Read(sourceBuffer, 0, count);\n            int sampleCount = sourceBytesRead \/ (bytesPerSample * channels);\n            for (int sample = 0; sample &lt; sampleCount; sample++)\n            {\n                int start = sample * bytesPerSample * channels;\n                double in1;\n                double in2;\n                ReadSamples(sourceBuffer, start, out in1, out in2);\n                simpleCompressor.Process(ref in1, ref in2);\n                WriteSamples(array, offset + start, in1, in2);\n            }\n            return count;\n        }\n        else\n        {\n            return sourceStream.Read(array, offset, count);\n        }\n    }\n \n}\n<\/pre><\/div>\n\n\n<p>Wita\u0107 tutaj, \u017ce przetwarzanie (czyli wywo\u0142anie simpleCompressor.Process&#8230; ) jest umieszczone w nadpisanej metodzie Read.<\/p>\n\n\n\n<p>Wykorzystanie klasy SimpleCompressorStream jest analogiczne jak w poprzednich przypadkach. Poni\u017cej funkcja odtwarzaj\u0105ca plik audio z zaaplikowanym kompresorem dynamiki. Oczywi\u015bcie pami\u0119ta\u0107 nale\u017cy o zwolnieniu zasob\u00f3w po zako\u0144czeniu odtwarzania. Polecam eksperymenty z doborem parametr\u00f3w Attack, Release, Ratio, Threshold oraz MakeUpGain w obiekcie klasy SimpleCompressorStream.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nNAudio.Wave.IWavePlayer waveOutDevice = new NAudio.Wave.WaveOut();\nNAudio.Wave.AudioFileReader audioFileReader;\nNAudio.Wave.SimpleCompressorStream compressor;\nprivate void PlayAudioFile(string fileName)\n{\n    try\n    {\n        CloseWaveOut();\n        waveOutDevice = new NAudio.Wave.WaveOut();\n        audioFileReader = new NAudio.Wave.AudioFileReader(fileName);\n        compressor = new SimpleCompressorStream(audioFileReader);\n        waveOutDevice.Init(compressor);\n        waveOutDevice.Play();\n \n    }\n    catch (Exception ex)\n    {\n        MessageBox.Show(string.Format(\"Wyst\u0105pi\u0142 b\u0142\u0105d: {0}\", ex.Message));\n    }\n}\n<\/pre><\/div>\n\n\n<p>W niniejszym artykule stara\u0142em si\u0119 przedstawi\u0107 najcz\u0119\u015bciej u\u017cywane funkcje biblioteki NAudio. Zach\u0119cam czytelnika do zapoznania si\u0119 z t\u0105 bibliotek\u0105, a tak\u017ce do analizy jej kod\u00f3w \u017ar\u00f3d\u0142owych z kt\u00f3rych mo\u017cna si\u0119 dowiedzie\u0107 wiele na temat przetwarzania danych audio.<\/p>\n\n\n<div class=\"kk-star-ratings kksr-auto kksr-align-left kksr-valign-bottom\"\n    data-payload='{&quot;align&quot;:&quot;left&quot;,&quot;id&quot;:&quot;2032&quot;,&quot;slug&quot;:&quot;default&quot;,&quot;valign&quot;:&quot;bottom&quot;,&quot;ignore&quot;:&quot;&quot;,&quot;reference&quot;:&quot;auto&quot;,&quot;class&quot;:&quot;&quot;,&quot;count&quot;:&quot;0&quot;,&quot;legendonly&quot;:&quot;&quot;,&quot;readonly&quot;:&quot;&quot;,&quot;score&quot;:&quot;0&quot;,&quot;starsonly&quot;:&quot;&quot;,&quot;best&quot;:&quot;5&quot;,&quot;gap&quot;:&quot;11&quot;,&quot;greet&quot;:&quot;&quot;,&quot;legend&quot;:&quot;0\\\/5 ( votes: 0)&quot;,&quot;size&quot;:&quot;18&quot;,&quot;title&quot;:&quot;NAudio - biblioteka do obs\u0142ugi audio w .NET cz. 2&quot;,&quot;width&quot;:&quot;0&quot;,&quot;_legend&quot;:&quot;{score}\\\/{best} ( {votes}: {count})&quot;,&quot;font_factor&quot;:&quot;1.25&quot;}'>\n            \n<div class=\"kksr-stars\">\n    \n<div class=\"kksr-stars-inactive\">\n            <div class=\"kksr-star\" data-star=\"1\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"2\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"3\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"4\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" data-star=\"5\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n    \n<div class=\"kksr-stars-active\" style=\"width: 0px;\">\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n            <div class=\"kksr-star\" style=\"padding-right: 11px\">\n            \n\n<div class=\"kksr-icon\" style=\"width: 18px; height: 18px;\"><\/div>\n        <\/div>\n    <\/div>\n<\/div>\n                \n\n<div class=\"kksr-legend\" style=\"font-size: 14.4px;\">\n            <span class=\"kksr-muted\"><\/span>\n    <\/div>\n    <\/div>\n","protected":false},"excerpt":{"rendered":"<p>W poprzednim artykule om\u00f3wi\u0142em podstawowe funkcje biblioteki NAudio. Przedstawi\u0142em w jaki spos\u00f3b odczytywa\u0107 pliki audio i je odtwarza\u0107. Dzisiaj zajmiemy &hellip; <a class=\"continued-btn\" href=\"https:\/\/sii.pl\/blog\/naudio-biblioteka-do-obslugi-audio-w-net-cz-2\/\">Continued<\/a><\/p>\n","protected":false},"author":77,"featured_media":2343,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_editorskit_title_hidden":false,"_editorskit_reading_time":0,"_editorskit_is_block_options_detached":false,"_editorskit_block_options_position":"{}","inline_featured_image":false,"footnotes":""},"categories":[1314],"tags":[129,249,273],"class_list":["post-2032","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development-na-twardo","tag-c","tag-audio","tag-naudio"],"acf":[],"aioseo_notices":[],"republish_history":[],"featured_media_url":"https:\/\/sii.pl\/blog\/wp-content\/uploads\/2016\/02\/Naudio-sii-blogersi.jpg","category_names":["Development na twardo"],"_links":{"self":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/2032"}],"collection":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/users\/77"}],"replies":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/comments?post=2032"}],"version-history":[{"count":2,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/2032\/revisions"}],"predecessor-version":[{"id":23464,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/posts\/2032\/revisions\/23464"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media\/2343"}],"wp:attachment":[{"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/media?parent=2032"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/categories?post=2032"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sii.pl\/blog\/wp-json\/wp\/v2\/tags?post=2032"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}