private void Form1_FormClosing(object sender, FormClosingEventArgs e)
 {
     DisposeWave();
     foreach (AudioFile file in this.files)
     {
         file.Stream.Dispose();
         file.Stream = null;
         if (file.Format == AudioFormats.MP3)
         {
             MP3File mp3file = file as MP3File;
             mp3file.Reader.Dispose();
             mp3file.Reader = null;
         }
         else
         {
             WaveFile wavfile = file as WaveFile;
             wavfile.Reader.Dispose();
             wavfile.Reader = null;
         }
     }
     for (int i = this.tmpCount; i > 0; i--)
     {
         File.Delete("tmp_" + i + ".wav");
     }
 }
        /* Методы перемотки */

        // Back
        private void back()
        {
            long position = this.currentAudio.Stream.Position;

            if (currentAudio.Format == AudioFormats.MP3)
            {
                MP3File file = currentAudio as MP3File;
                position = file.Reader.Position;
            }
            position = position - this.currentAudio.Stream.WaveFormat.AverageBytesPerSecond;
            if (position < 0)
            {
                position = 0;
                this.currentAudio.Stream.CurrentTime = new TimeSpan(0);
            }
            else
            {
                this.currentAudio.Stream.CurrentTime.Subtract(new TimeSpan(0, 0, 1));
            }
            this.currentAudio.Stream.Position = position;
            if (output.PlaybackState != PlaybackState.Playing)
            {
                originalPosition.CurrentTime = this.currentAudio.Stream.CurrentTime;
            }
        }
        private void deleteToolStripButton_Click(object sender, EventArgs e)
        {
            if (listAudio.SelectedItems.Count == 0)
            {
                return;
            }
            AudioFile file = files.Find(audio => audio.Path == listAudio.SelectedItems[0].SubItems[4].Text);

            listAudio.Items.Remove(listAudio.SelectedItems[0]);
            if (file == null)
            {
                return;
            }
            if (this.currentAudio == file)
            {
                if (output.PlaybackState == PlaybackState.Playing)
                {
                    originalPlayTimer.Stop();
                    spectrumTimer.Stop();
                    output.Stop();
                    originalCurrentTime.Text = "00:00:000";
                    audioStatus.Text         = "Готово";
                }
                audioNameLabel.Text             = "";
                audioFormatLabel.Text           = "";
                audioSizeLabel.Text             = "";
                audioSampleRateInfo.Text        = "";
                audioBitDepthInfo.SelectedIndex = -1;
                audioChannelsInfo.SelectedIndex = -1;
                viewPeriod.StartTime            = new TimeSpan(0);
                viewPeriod.EndTime              = new TimeSpan(0);
                audioRate.Text                  = "0 Hz";
                audioSize.Text                  = "0 MB";
                audioLength.Text                = "00:00:000";
                currentAudio                    = null;
                originalWaveViewer.WaveStream   = null;
                originalWaveViewer.Audio        = null;
                spectrumViewer.Audio            = null;
                originalSpectrogramViewer.Count = 0;
                originalSpectrogramViewer.Audio = null;
            }
            if (file.Format == AudioFormats.MP3)
            {
                MP3File deleteFile = file as MP3File;
                deleteFile.Reader.Dispose();
            }
            else if (file.Format == AudioFormats.WAV)
            {
                WaveFile deleteFile = file as WaveFile;
                deleteFile.Reader.Dispose();
            }
            currentAudioIndex = -1;
            file.Stream.Dispose();
            files.Remove(file);
            file = null;
            GC.Collect();
        }
        // Resample

        private void saveWavButton_Click(object sender, EventArgs e)
        {
            int sampleRate, bitDepth, channels;

            try {
                if (this.currentAudio == null)
                {
                    throw new Exception("Вы не выбрали файл для ресэмплинга.");
                }
                sampleRate = int.Parse(audioSampleRateInfo.Text);
            } catch (Exception ex) {
                MessageBox.Show(ex.Message, "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            bitDepth = int.Parse(audioBitDepthInfo.Text);
            channels = (audioChannelsInfo.SelectedIndex == 0) ? 1 : 2;
            SaveFileDialog save = new SaveFileDialog();

            save.Filter = "Wave File (*.wav)|*.wav;";
            if (save.ShowDialog() != DialogResult.OK)
            {
                return;
            }
            WaveFormat format = new WaveFormat(sampleRate, bitDepth, 1);
            WaveFormatConversionStream convertedStream = null;

            try {
                if (this.currentAudio.Format == AudioFormats.MP3)
                {
                    MP3File afile = this.currentAudio as MP3File;
                    convertedStream = new WaveFormatConversionStream(format, afile.Reader);
                }
                else
                {
                    WaveFile afile = this.currentAudio as WaveFile;
                    convertedStream = new WaveFormatConversionStream(format, afile.Reader);
                }
            } catch (Exception) {
                MessageBox.Show("Невозможно сконвертировать в данный формат.", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            WaveFileWriter.CreateWaveFile(save.FileName, convertedStream);
            DialogResult dres = MessageBox.Show("Аудиофайл успешно сохранен. Открыть файл?", "Файл сохранен", MessageBoxButtons.YesNo, MessageBoxIcon.Question);

            if (dres == DialogResult.Yes)
            {
                WaveFileReader            reader = new WaveFileReader(save.FileName);
                WaveStream                pcm    = new WaveChannel32(reader);
                BlockAlignReductionStream stream = new BlockAlignReductionStream(pcm);
                AudioFile file = new WaveFile(reader, stream, save.FileName);
                this.files.Add(file);
                this.addFileToListView(file);
                this.initAudio(file);
            }
        }
        private void openToolStripButton_Click(object sender, EventArgs e)
        {
            AudioFile      file = null;
            OpenFileDialog open = new OpenFileDialog();

            open.Filter = "Audio File (*.mp3;*.wav)|*.mp3;*.wav;";
            if (open.ShowDialog() != DialogResult.OK)
            {
                return;
            }
            AudioFile searchFile = files.Find(x => x.Path == open.FileName);

            if (searchFile != null)
            {
                MessageBox.Show("Этот файл уже добавлен в список.", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            try {
                if (open.FileName.EndsWith(".mp3"))
                {
                    Mp3FileReader             reader = new Mp3FileReader(open.FileName);
                    WaveStream                pcm    = WaveFormatConversionStream.CreatePcmStream(reader);
                    BlockAlignReductionStream stream = new BlockAlignReductionStream(pcm);
                    file = new MP3File(reader, stream, open.FileName);
                }
                else if (open.FileName.EndsWith(".wav"))
                {
                    WaveFileReader            reader = new WaveFileReader(open.FileName);
                    WaveStream                pcm    = new WaveChannel32(reader);
                    BlockAlignReductionStream stream = new BlockAlignReductionStream(pcm);
                    file = new WaveFile(reader, stream, open.FileName);
                }
                else
                {
                    throw new InvalidOperationException("Неверный формат аудиофайла");
                }
            } catch (Exception) {
                MessageBox.Show("Невозможно открыть файл. Возможно вы пытаетесь открыть закодированный файл. Попробуйте воспользоваться декодером G.711", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }
            files.Add(file);
            this.addFileToListView(file);
            if (files.Count == 1)
            {
                this.currentAudioIndex = 0;
                this.initAudio(file);
            }
        }
        private void originalPlayTimer_Tick(object sender, EventArgs e)
        {
            if (currentAudio == null)
            {
                return;
            }
            TimeSpan currentTime = new TimeSpan();

            if (currentAudio.Format == AudioFormats.MP3)
            {
                MP3File file = currentAudio as MP3File;
                currentTime = file.Reader.CurrentTime;
            }
            else if (currentAudio.Format == AudioFormats.WAV)
            {
                WaveFile file = currentAudio as WaveFile;
                currentTime = file.Reader.CurrentTime;
            }
            originalPosition.CurrentTime = currentTime;
        }
        // Forward
        private void forward()
        {
            long position = this.currentAudio.Stream.Position;

            if (currentAudio.Format == AudioFormats.MP3)
            {
                MP3File file = currentAudio as MP3File;
                position = file.Reader.Position;
            }
            if (position + this.currentAudio.Stream.WaveFormat.AverageBytesPerSecond > this.currentAudio.Stream.Length)
            {
                return;
            }
            this.currentAudio.Stream.Position = position + this.currentAudio.Stream.WaveFormat.AverageBytesPerSecond;
            this.currentAudio.Stream.CurrentTime.Add(new TimeSpan(0, 0, 1));
            if (output.PlaybackState != PlaybackState.Playing)
            {
                originalPosition.CurrentTime = this.currentAudio.Stream.CurrentTime;
            }
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            if (this.Audio != null)
            {
                long position = 0;
                if (audio.Format == Enums.AudioFormats.MP3)
                {
                    MP3File file = audio as MP3File;
                    position = file.Reader.Position / 2;
                }
                else if (audio.Format == Enums.AudioFormats.WAV)
                {
                    WaveFile file = audio as WaveFile;
                    position = file.Reader.Position / 2;
                }

                double[] spectrum = SpectrumViewer.getSpectrum(this.Audio, position);
                if (this.state == ViewState.LOGARITHM)
                {
                    this.logarithmSpectrum(spectrum);
                }

                e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
                Pen linePen = new Pen(this.PenColor, this.PenWidth);
                linePen.StartCap = System.Drawing.Drawing2D.LineCap.Round;
                linePen.EndCap   = System.Drawing.Drawing2D.LineCap.Round;

                float step = (float)(this.Width - 20) / spectrum.Length;

                // Отрисовка шкалы по оси X
                int yLinePos   = (this.state != ViewState.LOGARITHM) ? this.Height - 20 : 20;
                int yStringPos = (this.state != ViewState.LOGARITHM) ? yLinePos + 3 : 3;
                e.Graphics.DrawLine(Pens.White, 0, yLinePos, this.Width, yLinePos);
                e.Graphics.DrawString("kHz", new Font(FontFamily.GenericSansSerif, 7.5f), Brushes.White, 0, yStringPos);
                int[] freqPointsPercents = { 5, 10, 20, 25, 40, 50, 60, 75, 80, 90, 95 };   // Позиции значений частот (в %)
                float freqPoint;
                for (int i = 0; i < freqPointsPercents.Length; i++)
                {
                    freqPoint = 20 + (freqPointsPercents[i] * (this.Width - 20) / 100f);
                    if (this.state == ViewState.COLUMNAR || this.state == ViewState.DEFAULT)
                    {
                        e.Graphics.DrawLine(new Pen(Color.Gray, 1f), freqPoint, 0, freqPoint, this.Height - 20);
                    }
                    else
                    {
                        e.Graphics.DrawLine(new Pen(Color.Gray, 1f), freqPoint, 20, freqPoint, this.Height);
                    }
                    // Получение частоты в текущей точке и ее отображение
                    double sample      = (spectrum.Length * freqPointsPercents[i]) / 100.0;
                    string currentFreq = ((sample * freq) * Math.Pow(10, -3)).ToString("0.000");
                    e.Graphics.DrawString(currentFreq, new Font(FontFamily.GenericSansSerif, 7.5f), Brushes.White, freqPoint - 15, yStringPos);
                }

                // Отрисовка шкалы по оси Y
                e.Graphics.DrawLine(Pens.White, 20, 0, 20, this.Height);
                if (this.state == ViewState.LOGARITHM)
                {
                    e.Graphics.DrawString("dB", new Font(FontFamily.GenericSansSerif, 7.5f), Brushes.White, 2, this.Height - 15);
                }
                int[]  gradePointsPercents = { 10, 20, 30, 40, 50, 60, 70, 80, 90 }; // Позиции значений уровня спектра (в %)
                int    gradePoint;
                double currentGrade;
                for (int i = 0; i < gradePointsPercents.Length; i++)
                {
                    if (i == gradePointsPercents.Length - 1 && this.state == ViewState.LOGARITHM)
                    {
                        break;                                                                              // Для dB не выводить последнее значение
                    }
                    gradePoint = gradePointsPercents[i] * (this.Height - 20) / 100;
                    gradePoint = (this.state == ViewState.LOGARITHM) ? gradePoint + 20 : gradePoint;
                    e.Graphics.DrawLine(new Pen(Color.Gray, 1f), 20, gradePoint, this.Width, gradePoint);
                    if (this.state != ViewState.LOGARITHM)
                    {
                        // Нормировка значения уровня спектра
                        currentGrade = (this.Height - 20 - gradePoint) * this.Audio.Avg / (this.Height - 20);
                        if (this.state == ViewState.COLUMNAR)
                        {
                            currentGrade /= 3;
                        }
                        currentGrade *= 10000;
                        currentGrade  = Math.Round(currentGrade);
                    }
                    else
                    {
                        currentGrade = Math.Round(gradePoint / -1.5);
                    }
                    e.Graphics.DrawString(currentGrade.ToString(), new Font(FontFamily.GenericSansSerif, 7f), Brushes.White, -1, gradePoint - 6);
                }

                // Отрисовка спектра
                float koef = (this.state != ViewState.LOGARITHM) ? (this.Height - 20) / this.Audio.Avg : 1.5f;

                float x = e.ClipRectangle.X + 20;
                float y = (float)(this.Height - 20);
                y = (this.state == ViewState.LOGARITHM) ? 20 : y;
                if (this.state != ViewState.COLUMNAR)   // Для грфаического представления
                {
                    float x1, y1;
                    for (int i = 1; i < spectrum.Length; i++)
                    {
                        x1 = x + step;
                        y1 = (this.state != ViewState.LOGARITHM) ? (this.Height - 20) - (float)(spectrum[i] * koef) : 20 - (float)(spectrum[i] * koef);
                        if (float.IsInfinity(y1))
                        {
                            continue;
                        }
                        e.Graphics.DrawLine(linePen, x, y, x1, y1);
                        x = x1; y = y1;
                    }
                }
                else        // Для столбчатого
                {
                    float columnWidth  = (float)(this.Width - 20) / this.columnCount;
                    float columnHeight = 0;
                    float columnHeightCoord;
                    float oldLineYCoord;
                    for (int i = 0; i < this.columnCount; i++, columnHeight = 0)
                    {
                        // Находим среднее значение уровня для текущего столбца
                        for (int j = i * (spectrum.Length / this.columnCount), count = 0; count < (spectrum.Length / this.columnCount); j++, count++)
                        {
                            if (i == 0 && j == 0)
                            {
                                continue;
                            }
                            columnHeight += (float)spectrum[j];
                        }
                        columnHeight      /= (i == 0) ? (spectrum.Length / this.columnCount) - 1 : spectrum.Length / this.columnCount;
                        this.oldValues[i] -= 0.00005f; // Плавное падение полосы-указателя предыдущего уровня
                        oldLineYCoord      = (this.Height - 20) - this.oldValues[i] * koef * 3;
                        if (columnHeight > this.oldValues[i])
                        {
                            this.oldValues[i] = columnHeight;   // Обновление указателя уровня
                        }
                        columnHeightCoord = (this.Height - 20) - columnHeight * koef * 3;
                        e.Graphics.DrawLine(linePen, x, oldLineYCoord, x + columnWidth, oldLineYCoord);
                        e.Graphics.DrawRectangle(Pens.Aqua, x, columnHeightCoord, columnWidth, y - columnHeightCoord);
                        x += columnWidth;
                    }
                }
            }
            base.OnPaint(e);
        }