예제 #1
0
        void PlaySound(string link, int WaveOutDeviceId)
        {
            using (Stream ms = new MemoryStream())
            {
                using (Stream stream = WebRequest.Create(link).GetResponse().GetResponseStream())
                {
                    byte[] buffer = new byte[4096];
                    int    read;
                    while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
                    {
                        ms.Write(buffer, 0, read);
                    }
                }

                ms.Position = 0;
                using (WaveStream mf = new BlockAlignReductionStream(WaveFormatConversionStream.CreatePcmStream(new Mp3FileReader(ms))))
                    using (var wo = new WaveOutEvent())
                    {
                        wo.DeviceNumber           = WaveOutDeviceId;
                        PitchProvider             = new SmbPitchShiftingSampleProvider(mf.ToSampleProvider().ToMono());
                        PitchProvider.PitchFactor = Pitch;
                        wo.Init(PitchProvider);
                        wo.Volume = VoiceVolume;
                        wo.Play();
                        while (wo.PlaybackState == PlaybackState.Playing)
                        {
                            PitchProvider.PitchFactor = Pitch;
                            wo.Volume = VoiceVolume;
                            Thread.Sleep(500);
                        }
                    }
            }
        }
예제 #2
0
        private void btnDownload_Click(object sender, EventArgs e)
        {
            string         soundLink = GetGUISoundLink();
            SaveFileDialog dialog    = new SaveFileDialog();

            dialog.Filter   = "MP3 File (*.mp3)|*.mp3";
            dialog.FileName = "tts.mp3";
            var s = dialog.ShowDialog();

            if (s == DialogResult.OK)
            {
                if (!Program.bOldWindows)
                {
                    using (var mf = new MediaFoundationReader(soundLink))
                    {
                        PitchProvider             = new SmbPitchShiftingSampleProvider(mf.ToSampleProvider().ToMono());
                        PitchProvider.PitchFactor = Pitch;
                        MediaFoundationEncoder.EncodeToMp3(PitchProvider.ToWaveProvider(), dialog.FileName, 48000);
                        MessageBox.Show(downloaded);
                    }
                }
                else
                {
                    using (var wc = new WebClient())
                    {
                        wc.DownloadFile(soundLink, dialog.FileName);
                        MessageBox.Show(downloaded);
                    }
                }
            }
        }
예제 #3
0
        private SmbPitchShiftingSampleProvider DoModificado(double exponente)
        {
            var nota_do         = NotaDo();
            var nota_modificada = new SmbPitchShiftingSampleProvider(nota_do);

            nota_modificada.PitchFactor = (float)Math.Pow(2.0, exponente);
        }
예제 #4
0
        public static ISampleProvider PitchShift(ISampleProvider sample, int correction)
        {
            float factor = (float)Math.Pow(2, correction / 12f);
            SmbPitchShiftingSampleProvider shifter = new SmbPitchShiftingSampleProvider(sample, 1024, 4, factor);

            return(shifter);
        }
예제 #5
0
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            string fileDir     = AppContext.BaseDirectory;
            var    inPath      = SPath.Combine(fileDir, "了解真相快三退.wav");
            var    semitone    = Math.Pow(2, 1.0 / 12);
            var    upOneTone   = semitone * semitone * semitone * semitone * semitone;
            var    downOneTone = 1.0 / (upOneTone);
            var    tfile       = TagLib.File.Create(inPath);

            using (var reader = new MediaFoundationReader(inPath))
            {
                var pitch = new SmbPitchShiftingSampleProvider(reader.ToSampleProvider());
                pitch.PitchFactor = (float)(((double)new Random().Next(60, 115)) / 100);
                string tempFileNameGuid   = Guid.NewGuid().ToString();
                string tempFilePath       = SPath.Combine(fileDir, tempFileNameGuid + ".wav");
                string outputFileNameGuid = Guid.NewGuid().ToString();
                string outWavFilePath     = SPath.Combine(fileDir, outputFileNameGuid + ".wav");
                string outMp3FilePath     = SPath.Combine(fileDir, outputFileNameGuid + ".mp3");
                WaveFileWriter.CreateWaveFile(tempFilePath, pitch.ToWaveProvider());
                ConvertWavToMp3(tempFilePath, outMp3FilePath, tfile.Properties.AudioBitrate);
                //playSampleProvider(pitch);
                using (var mp3Reader = new Mp3FileReader(outMp3FilePath))
                    using (var conversionStream = new WaveFormatConversionStream(reader.WaveFormat, mp3Reader))
                        WaveFileWriter.CreateWaveFile(outWavFilePath, conversionStream);
                if (File.Exists(tempFilePath))
                {
                    File.Delete(tempFilePath);
                }
            }
        }
예제 #6
0
        private void BtnDoSos_Click(object sender, RoutedEventArgs e)
        {
            var nota_do    = NotaDo();
            var nota_doSos = new SmbPitchShiftingSampleProvider(nota_do);

            nota_doSos.PitchFactor = (float)Math.Pow(2.0, 1.0 / 12.0);
            mixer.AddMixerInput(nota_doSos);
        }
예제 #7
0
        private ISampleProvider CModificado(double exponente)
        {
            var nota_c          = NotaC();
            var nota_modificada = new SmbPitchShiftingSampleProvider(nota_c);

            nota_modificada.PitchFactor = (float)(Math.Pow(2.0, exponente));

            return(nota_modificada);
        }
예제 #8
0
        private IEnumerator StartPlaying()
        {
            try
            {
                this.starting = true;
                LockControls();

                string         songsDirectory = this.GetSongsDirectory();
                PrepareSongJob prepareSongJob = new PrepareSongJob(songsDirectory);
                prepareSongJob.Start();
                yield return(this.EquippableModComponent.StartCoroutine(prepareSongJob.WaitFor()));

                if (prepareSongJob.SelectedSong == null)
                {
                    HUDMessage.AddMessage("[Instrument-Pack]: No songs in directory '" + songsDirectory + "'");
                    yield break;
                }

                Debug.Log("[Instrument-Pack]: Selected song " + prepareSongJob.SelectedSong);

                this.reader = prepareSongJob.Reader;
                if (this.reader == null)
                {
                    HUDMessage.AddMessage("[Instrument-Pack]: Cannot play song '" + prepareSongJob.SelectedSong + "'.", 10, true);
                    yield break;
                }

                this.reader.Volume = TARGET_VOLUME * InterfaceManager.m_Panel_OptionsMenu.m_State.m_MasterVolume / prepareSongJob.MaxSample;

                this.pitchShifter = new SmbPitchShiftingSampleProvider(reader);

                this.waveOutEvent = new WaveOutEvent();
                this.waveOutEvent.PlaybackStopped += this.OnPlaybackStopped;
                this.waveOutEvent.Init(pitchShifter);
                this.waveOutEvent.Play();

                if (this.EquippableModComponent.EquippedModel != null)
                {
                    Playing playing = ModUtils.GetOrCreateComponent <Playing>(this.EquippableModComponent.EquippedModel);
                    playing.Instrument   = this;
                    playing.MistakeAudio = this.MistakeAudio;
                    playing.RefreshSkillEffect();
                }
                else
                {
                    // the equipped model is gone -> stop playing
                    StopPlaying();
                }
            }
            finally
            {
                this.starting = false;
            }
        }
예제 #9
0
        private void btnDownload_Click(object sender, EventArgs e)
        {
            string soundLink = GetGUISoundLink();

            if (soundLink == "")
            {
                return;
            }
            SaveFileDialog dialog = new SaveFileDialog();

            if (radio_mp3.Checked)
            {
                dialog.Filter   = "MP3 File (*.mp3)|*.mp3";
                dialog.FileName = "tts.mp3";
            }
            else
            {
                dialog.Filter   = "WAV File (*.wav)|*.wav";
                dialog.FileName = "tts.wav";
            }

            var s = dialog.ShowDialog();

            if (s == DialogResult.OK)
            {
                if (!Program.bOldWindows && !(radio_mp3.Checked && Math.Abs(Pitch - 1f) <= 0.01f))
                {
                    using (var mf = new MediaFoundationReader(soundLink))
                    {
                        PitchProvider             = new SmbPitchShiftingSampleProvider(mf.ToSampleProvider().ToMono());
                        PitchProvider.PitchFactor = Pitch;
                        if (radio_mp3.Checked)
                        {
                            MediaFoundationEncoder.EncodeToMp3(PitchProvider.ToWaveProvider(), dialog.FileName, 48000);
                        }
                        else
                        {
                            WaveFileWriter.CreateWaveFile(dialog.FileName, PitchProvider.ToWaveProvider());
                        }

                        MessageBox.Show(downloaded);
                    }
                }
                else
                {
                    using (var wc = new WebClient())
                    {
                        wc.DownloadFile(soundLink, dialog.FileName);
                        MessageBox.Show(downloaded);
                    }
                }
            }
        }
예제 #10
0
    static private async Task ChangePitch()
    {
        pitchStream = new SmbPitchShiftingSampleProvider(input);

        using (device = new WaveOutEvent())
        {
            device.Init(pitchStream);
            device.Play();
            while (device.PlaybackState == PlaybackState.Playing)
            {
                await Task.Delay(2000);
            }
        }
    }
예제 #11
0
        public WaveStream Pitch(WaveStream w, IMessage m, float PitchFactor)
        {
            string filePath = $"Commands{Path.DirectorySeparatorChar}Edit{Path.DirectorySeparatorChar}pitch.bin";

            lock (pitchLock)
            {
                SmbPitchShiftingSampleProvider pitch = new SmbPitchShiftingSampleProvider(w.ToSampleProvider())
                {
                    PitchFactor = PitchFactor
                };

                WaveFileWriter.CreateWaveFile16(filePath, pitch);
                return(new WaveFileReader(filePath));
            }
        }
예제 #12
0
        private void btn_stop_Click(object sender, EventArgs e)
        {
            if (output != null)
            {
                btn_stop.Enabled     = false;
                btn_pause.Enabled    = false;
                vsb_volumeL.Enabled  = false;
                vsb_volumeR.Enabled  = false;
                vsb_volumeM.Enabled  = false;
                trb_progress.Enabled = false;
                cb_controle.Enabled  = false;
                progressBar1.Value   = 0;
                progressBar2.Value   = 0;
                progressBar3.Value   = 0;
                progressBar4.Value   = 0;
                progressBar6.Value   = 0;
                progressBar7.Value   = 0;
                progressBar8.Value   = 0;
                btn_pause.Text       = "Play";
                lb_name.Text         = "";
                lb_length.Text       = "";
                trb_progress.Value   = 0;
                lb_decTime.Text      = "";

                if (output != null)
                {
                    if (output.PlaybackState == NAudio.Wave.PlaybackState.Playing)
                    {
                        output.Stop();
                    }
                    output.Dispose();
                    output = null;
                }
                if (stream != null)
                {
                    stream.Dispose();
                    stream = null;
                }
                if (pitch != null)
                {
                    pitch = null;
                }
                if (stereo != null)
                {
                    stereo = null;
                }
            }
        }
예제 #13
0
 private void toolStripMenuItem4_Click(object sender, EventArgs e)
 {
     try
     {
         outputDevice.Stop();
         SmbPitchShiftingSampleProvider provider = new SmbPitchShiftingSampleProvider(foundationReader.ToSampleProvider());
         provider.PitchFactor = 2f;
         if (provider.PitchFactor == 0)
         {
             provider.PitchFactor = 0.5f;
         }
         outputDevice.Init(provider);
         outputDevice.Play();
     }
     catch { }
 }
예제 #14
0
 private void Form1_FormClosing(object sender, FormClosingEventArgs e)
 {
     if (output != null)
     {
         if (output.PlaybackState == NAudio.Wave.PlaybackState.Playing)
         {
             output.Stop();
         }
         output.Dispose();
         output = null;
     }
     if (stream != null)
     {
         stream.Dispose();
         stream = null;
     }
     if (pitch != null)
     {
         pitch = null;
     }
     if (stereo != null)
     {
         stereo = null;
     }
     closing = true;
     if (capture != null && capture.CaptureState == NAudio.CoreAudioApi.CaptureState.Capturing)
     {
         capture.StopRecording();
     }
     if (wo != null)
     {
         if (wo.PlaybackState == PlaybackState.Playing)
         {
             wo.Stop();
         }
         wo.Dispose();
     }
     waveIn.StopRecording();
     writer?.Dispose();
     wo      = null;
     waveIn  = null;
     capture = null;
     writer  = null;
 }
예제 #15
0
 void PlaySound(string link, int WaveOutDeviceId)
 {
     using (var mf = new MediaFoundationReader(link))
         using (var wo = new WaveOutEvent())
         {
             wo.DeviceNumber           = WaveOutDeviceId;
             PitchProvider             = new SmbPitchShiftingSampleProvider(mf.ToSampleProvider().ToMono());
             PitchProvider.PitchFactor = Pitch;
             wo.Init(PitchProvider);
             wo.Volume = VoiceVolume;
             wo.Play();
             while (wo.PlaybackState == PlaybackState.Playing)
             {
                 PitchProvider.PitchFactor = Pitch;
                 wo.Volume = VoiceVolume;
                 Thread.Sleep(500);
             }
         }
 }
예제 #16
0
        /// <summary>
        /// Питч-шифтинг по данным из формы
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            var inPath      = rfn;
            var semitone    = Math.Pow(2, 1.0 / 12);
            var upOneTone   = semitone * semitone;
            var downOneTone = 1.0 / upOneTone;

            using (var reader = new MediaFoundationReader(inPath))
            {
                var pitch = new SmbPitchShiftingSampleProvider(reader.ToSampleProvider());
                using (var device = new WaveOutEvent())
                {
                    if (listBox1.SelectedIndex == 0)
                    {
                        pitch.PitchFactor = (float)upOneTone * trackBar1.Value * (float)0.25;
                    }
                    else
                    {
                        pitch.PitchFactor = (float)downOneTone * trackBar1.Value * (float)0.042;
                    }
                    SaveFileDialog save = new SaveFileDialog();
                    save.InitialDirectory = "C:\\";
                    save.Filter           = "wav files (*.wav)|*.wav";
                    save.FilterIndex      = 1;
                    save.Title            = "Сохранить файл";
                    if (save.ShowDialog() == DialogResult.Cancel)
                    {
                        return;
                    }
                    string filename = save.FileName;
                    if (filename != null)
                    {
                        WaveFileWriter.CreateWaveFile(filename, pitch.ToWaveProvider16());
                        MessageBox.Show("Файл сохранен!");
                        this.Close();
                    }
                    else
                    {
                        System.Windows.Forms.MessageBox.Show("Не выбран путь сохранения!", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    }
                }
            }
        }
예제 #17
0
        public void wasapiPlay()
        {
            ISampleProvider                sampleProvider1;
            VolumeSampleProvider           volumeSampleProv1;
            SmbPitchShiftingSampleProvider smbPitchSampleProv1;
            OffsetSampleProvider           offsetSampleProv1;
            PanningSampleProvider          panSampleProv1;

            void funcForBuff(object sender, WaveInEventArgs waveInEventArgs)
            {
                buffWaveProv.AddSamples(waveInEventArgs.Buffer, 0, waveInEventArgs.BytesRecorded);
            }

            var enumerator = new NAudio.CoreAudioApi.MMDeviceEnumerator();

            wInput  = enumerator.GetDevice(strInputDeviceID);
            wOutput = enumerator.GetDevice(strOutputDeviceID);

            wOut     = new WasapiOut(wOutput, AudioClientShareMode.Shared, true, 10);
            wCapture = new WasapiCapture(wInput, true, 10);

            buffWaveProv = new BufferedWaveProvider(wCapture.WaveFormat);

            wCapture.DataAvailable += funcForBuff;

            sampleProvider1                 = buffWaveProv.ToSampleProvider();
            smbPitchSampleProv1             = new SmbPitchShiftingSampleProvider(sampleProvider1);
            smbPitchSampleProv1.PitchFactor = fPitch;

            offsetSampleProv1         = new OffsetSampleProvider(smbPitchSampleProv1);
            offsetSampleProv1.DelayBy = new TimeSpan(0, 0, 0, 0, iLatency);

            panSampleProv1     = new PanningSampleProvider(offsetSampleProv1.ToMono(1f, 1f));
            panSampleProv1.Pan = fPanning;

            volumeSampleProv1        = new VolumeSampleProvider(panSampleProv1);
            volumeSampleProv1.Volume = fVolume;

            wOut.Init(volumeSampleProv1);
            wCapture.StartRecording();
            wOut.Play();
        }
예제 #18
0
        public void Start()
        {
            this._waveOut?.Dispose();

            // Stop → Init だと WASAPI がエラー出すので作り直す
            this._waveOut = new WasapiOut(AudioClientShareMode.Shared, true, 50);
            this._waveOut.PlaybackStopped += this.WaveOutPlaybackStopped;

            // ISampleProvider をつくる
            // SmbPitchShiftingSampleProvider は内部でバッファーを持っているので、使いまわせない
            this._pitchShiftProvider = new SmbPitchShiftingSampleProvider(this._monoSampleProvider, 1024, 2, 1f);
            //this._pitchShiftProvider = new StftPitchShiftingSampleProvider(this._monoSampleProvider);
            var provider = new PanningSampleProvider(this._pitchShiftProvider)
            {
                Pan = this._pan
            };

            this._waveOut.Init(provider);
            this._waveOut.Play();
        }
예제 #19
0
        protected void BuildWaveOut()
        {
            WaveOut?.Dispose();
            FileReader?.Dispose();

            FileReader          = new AudioFileReader(FilePath);
            FileReader.Position = (ActiveCue?.StartPosition) ?? 0;
            FadeControl         = new FadeInOutSampleProvider(FileReader, ActiveCue?.StartSilent ?? false);
            if (ActiveCue != null && (ActiveCue?.FadeInTime) > 0)
            {
                FadeControl.BeginFadeIn(ActiveCue?.FadeInTime ?? 0);
            }
            //if (ActiveCue != null && (ActiveCue?.FadeOutTime) > 0) FadeControl.(ActiveCue?.FadeInTime ?? 0);
            //TODO: FadeOutMonitor?

            PitchControl             = new SmbPitchShiftingSampleProvider(FadeControl);
            PitchControl.PitchFactor = ActiveCue?.PitchFactor ?? 1;
            WaveOut = new WaveOutEvent();
            WaveOut.Init(PitchControl);
        }
예제 #20
0
        private void btnVoicePlay_Click(object sender, EventArgs e)
        {
            // From https://github.com/naudio/NAudio/blob/master/Docs/SmbPitchShiftingSampleProvider.md. Pitch changing outside Unity is weird.
            string inPath      = DataDirectory.Path + @"\BaseVoices\" + cmbVoiceType.Text + ".wav";
            double semitone    = Math.Pow(2, 1.0 / 12);
            double upOneTone   = semitone * semitone;
            double downOneTone = 1.0 / upOneTone;
            double targetPitch = ((double)nudPitch.Value + (-0.1 + RNG.NextDouble() / 5)) * semitone;

            using (var reader = new MediaFoundationReader(inPath))
            {
                var pitch = new SmbPitchShiftingSampleProvider(reader.ToSampleProvider());
                using (var device = new WaveOutEvent())
                {
                    pitch.PitchFactor = (float)targetPitch;
                    device.Init(pitch.Take(TimeSpan.FromSeconds(5)));
                    //device.Init(new AudioFileReader(inPath));
                    device.Play();
                    System.Threading.Thread.Sleep(400);
                }
            }
        }
예제 #21
0
        private void btn_open_Click(object sender, EventArgs e)
        {
            OpenFileDialog open = new OpenFileDialog();

            open.Filter = "MP3 File (*.mp3)|*.mp3|WAV File (*.wav)|*.wav";
            if (open.ShowDialog() != DialogResult.OK)
            {
                return;
            }

            output = new WaveOutEvent();
            stream = new AudioFileReader(open.FileName);
            pitch  = new SmbPitchShiftingSampleProvider(stream.ToSampleProvider());

            pitch.PitchFactor = 1;
            stereo            = new MonoToStereoSampleProvider(pitch.ToMono());

            output.Init(stereo);

            stereo.RightVolume = 0.5f;
            stereo.LeftVolume  = 0.5f;
            stream.Volume      = 0.5f;

            lb_name.Text    = open.SafeFileName;
            lb_length.Text  = stream.TotalTime.ToString().Remove(8);
            lb_length.Text += " sec.";
            lb_decTime.Text = stream.CurrentTime.ToString();

            btn_pause.Enabled    = true;
            btn_stop.Enabled     = true;
            vsb_volumeL.Enabled  = true;
            vsb_volumeM.Enabled  = true;
            vsb_volumeR.Enabled  = true;
            trb_progress.Enabled = true;
            cb_controle.Enabled  = true;

            trb_progress.Maximum = (int)stream.TotalTime.TotalSeconds;
        }
예제 #22
0
 public void Stop()
 {
     this._waveOut?.Stop();
     this._buffer.ClearBuffer();
     this._pitchShiftProvider = null;
 }
        /// <summary>
        /// Uses the Windows TTS library to get the bytes of a PCM Wave file from a text messages.
        /// </summary>
        /// <param name="message"></param>
        /// <param name="voiceName"></param>
        /// <returns>The way files bytes, or an empty array if something went wrong.</returns>
        public byte[] GenerateRadioMessageWavBytesFromTTS(string message, string voiceName = null)
        {
            // Media files are stored in the Release build directory, so if we're running a Debug build, we have to look for them here.
            string debugPathToRelease = "";

#if DEBUG
            debugPathToRelease = "..\\Release\\";
#endif

            if (string.IsNullOrEmpty(message))
            {
                message = "";                                // Make sure message is not null
            }
            // No voice name provided, use the default voice instead
            if (voiceName == null)
            {
                if (DefaultVoice == null) // Default voice not set/doesn't exist
                {
                    return(new byte[0]);
                }

                voiceName = DefaultVoice;
            }

            try { Reader.SelectVoice(voiceName); }
            catch (Exception) { return(new byte[0]); }

            // Text-to-speech
            MemoryStream ttsStream = new MemoryStream();            // create a new memory stream
            Reader.SetOutputToWaveStream(ttsStream);                // set the stream as output for the TTS reader
            Reader.Volume = 35;
            Reader.Speak(message);                                  // read the text into the stream
            ttsStream.Seek(0, SeekOrigin.Begin);                    // rewind the stream to position 0
            WaveFileReader waveTTS = new WaveFileReader(ttsStream); // read the stream into a WaveFileReader object

            SmbPitchShiftingSampleProvider pitchProvider = new SmbPitchShiftingSampleProvider(waveTTS.ToSampleProvider())
            {
                PitchFactor = 1f + Pitch_ * .005f
            };

            // Mix voice with radio static
            WaveFileReader  waveStatic     = new WaveFileReader(debugPathToRelease + "Media/Loop.wav"); // load the static sound loop
            ISampleProvider providerSpeech = new AMRadioFilter(pitchProvider, FXIntensity * 250);       // get the sample provider for the TTS, apply a radio filter

            ISampleProvider providerStatic = waveStatic.ToSampleProvider();                             // get the sample provider for the static
            TimeSpan        ttsDuration    = waveTTS.TotalTime;                                         // get the tts wave duration
            if (ttsDuration < TimeSpan.FromSeconds(MIN_SPEECH_DURATION))
            {
                ttsDuration = TimeSpan.FromSeconds(MIN_SPEECH_DURATION);                                                          // check min value
            }
            if (ttsDuration > TimeSpan.FromSeconds(MAX_SPEECH_DURATION))
            {
                ttsDuration = TimeSpan.FromSeconds(MAX_SPEECH_DURATION);                                                 // check max value
            }
            ISampleProvider[]    sources = new[] { providerSpeech.Take(ttsDuration), providerStatic.Take(ttsDuration) }; // use both providers as source with a duration of ttsDuration
            MixingSampleProvider mixingSampleProvider = new MixingSampleProvider(sources);                               // mix both channels
            IWaveProvider        radioMix             = mixingSampleProvider.ToWaveProvider16();                         // convert the mix output to a PCM 16bit sample provider

            // Concatenate radio in/out sounds
            WaveFileReader  waveRadioIn  = new WaveFileReader(debugPathToRelease + "Media/In.wav");     // load the radio in FX
            WaveFileReader  waveRadioOut = new WaveFileReader(debugPathToRelease + "Media/Out.wav");    // load the radio out FX
            IWaveProvider[] radioFXParts = new IWaveProvider[] { waveRadioIn, radioMix, waveRadioOut }; // create an array with all 3 parts

            byte[]         buffer         = new byte[1024];                                             // create a buffer to store wav data to concatenate
            MemoryStream   finalWavStr    = new MemoryStream();                                         // create a stream for the final concatenated wav
            WaveFileWriter waveFileWriter = null;                                                       // create a writer to fill the stream

            foreach (IWaveProvider wav in radioFXParts)                                                 // iterate all three parts
            {
                if (waveFileWriter == null)                                                             // no writer, first part of the array
                {
                    waveFileWriter = new WaveFileWriter(finalWavStr, wav.WaveFormat);                   // create a writer of the proper format
                }
                else if (!wav.WaveFormat.Equals(waveFileWriter.WaveFormat))                             // else, check the other parts are of the same format
                {
                    continue;                                                                           // file is not of the proper format
                }
                int read;                                                                               // bytes read
                while ((read = wav.Read(buffer, 0, buffer.Length)) > 0)                                 // read data from the wave
                {
                    waveFileWriter.Write(buffer, 0, read);
                }                                          // fill the buffer with it
            }

            // Copy the stream to a byte array
            waveFileWriter.Flush();
            finalWavStr.Seek(0, SeekOrigin.Begin);
            byte[] waveBytes = new byte[finalWavStr.Length];
            finalWavStr.Read(waveBytes, 0, waveBytes.Length);

            // Close/dispose of everything
            ttsStream.Close(); ttsStream.Dispose();
            waveTTS.Close(); waveTTS.Dispose();
            waveStatic.Close(); waveStatic.Dispose();
            waveRadioIn.Close(); waveRadioIn.Dispose();
            waveRadioOut.Close(); waveRadioOut.Dispose();
            waveFileWriter.Close(); waveFileWriter.Dispose();
            finalWavStr.Close(); finalWavStr.Dispose();

            // Return the bytes
            return(waveBytes);
        }