コード例 #1
0
        static void ApplyPitch(PlayItem item)
        {
            // Get info about the WAV.
            int sampleRate    = item.WavHead.SampleRate;
            int bitsPerSample = item.WavHead.BitsPerSample;
            int channelCount  = item.WavHead.Channels;
            // Get info about effects and pitch.
            var ms     = new MemoryStream();
            var writer = new System.IO.BinaryWriter(ms);
            var bytes  = item.WavData;
            // Add 100 milliseconds at the start.
            var silenceStart = 100;
            // Add 200 milliseconds at the end.
            var silenceEnd   = 200;
            var silenceBytes = AudioHelper.GetSilenceByteCount(sampleRate, bitsPerSample, channelCount, silenceStart + silenceEnd);

            // Comment WriteHeader(...) line, because SharpDX don't need that (it creates noise).
            //AudioHelper.WriteHeader(writer, bytes.Length + silenceBytes, channelCount, sampleRate, bitsPerSample);
            if (ApplyEffects)
            {
                token = new CancellationTokenSource();
                // This part could take long time.
                bytes = EffectsGeneral.ApplyPitchShift(bytes, channelCount, sampleRate, bitsPerSample, PitchShift, token);
                // If pitch shift was canceled then...
                if (token.IsCancellationRequested)
                {
                    return;
                }
            }
            // Add silence at the start to make room for effects.
            Audio.AudioHelper.WriteSilenceBytes(writer, sampleRate, bitsPerSample, channelCount, silenceStart);
            writer.Write(bytes);
            // Add silence at the back to make room for effects.
            Audio.AudioHelper.WriteSilenceBytes(writer, sampleRate, bitsPerSample, channelCount, silenceEnd);
            // Add result to play list.
            item.WavData = ms.ToArray();
            //System.IO.File.WriteAllBytes("Temp.wav", item.Data);
            var duration = ((decimal)bytes.Length * 8m) / (decimal)channelCount / (decimal)sampleRate / (decimal)bitsPerSample * 1000m;

            duration     += (silenceStart + silenceEnd);
            item.Duration = (int)duration;
        }
コード例 #2
0
        /// <summary>
        /// Load sound data. wavData must not contain WAV Head.
        /// </summary>
        /// <param name="wavBytes"></param>
        /// <returns>Returns duration.</returns>
        public decimal Load(byte[] wavBytes, int sampleRate, int bitsPerSample, int channelCount)
        {
            var format = new SharpDX.Multimedia.WaveFormat(sampleRate, bitsPerSample, channelCount);
            // Create and set the buffer description.
            var desc = new SoundBufferDescription();

            desc.Format = format;
            desc.Flags  =
                // Play sound even if application loses focus.
                BufferFlags.GlobalFocus |
                // This has to be true to use effects.
                BufferFlags.ControlEffects;
            desc.BufferBytes = wavBytes.Length;
            // Create and set the buffer for playing the sound.
            ApplicationBuffer = new SecondarySoundBuffer(ApplicationDevice, desc);
            ApplicationBuffer.Write(wavBytes, 0, LockFlags.None);
            var duration = AudioHelper.GetDuration(wavBytes.Length, sampleRate, bitsPerSample, channelCount);

            return(duration);
        }
コード例 #3
0
        /// <summary>
        /// Convert XML to WAV bytes. WAV won't have the header, so you have to add it separately.
        /// </summary>
        static void ConvertXmlToWav(PlayItem item)
        {
            var query = System.Web.HttpUtility.ParseQueryString(item.VoiceSourceKeys ?? "");
            // Default is local.
            var source = VoiceSource.Local;

            Enum.TryParse(query[InstalledVoiceEx._KeySource], true, out source);
            var voiceId = query[InstalledVoiceEx._KeyVoiceId];

            byte[] wavBytes;
            if (source == VoiceSource.Amazon)
            {
                var region = query[InstalledVoiceEx._KeyRegion];
                var engine = query[InstalledVoiceEx._KeyEngine];
                var client = new Voices.AmazonPolly(
                    SettingsManager.Options.AmazonAccessKey,
                    SettingsManager.Options.AmazonSecretKey,
                    region
                    );
                wavBytes = client.SynthesizeSpeech(voiceId, item.Xml, Amazon.Polly.OutputFormat.Mp3, engine);
                if (wavBytes != null && wavBytes.Length > 0)
                {
                    var pi = DecodeToPlayItem(wavBytes);
                    item.WavHead  = pi.WavHead;
                    item.WavData  = pi.WavData;
                    item.Duration = pi.Duration;
                    pi.Dispose();
                }
            }
            else
            {
                wavBytes = ConvertSsmlXmlToWav(voiceId, item.Xml, item.WavHead);
                if (wavBytes != null && wavBytes.Length > 0)
                {
                    item.WavData  = wavBytes;
                    item.Duration = AudioHelper.GetDuration(wavBytes.Length, item.WavHead.SampleRate, item.WavHead.BitsPerSample, item.WavHead.Channels);
                }
            }
        }
コード例 #4
0
        // Returns left and right float arrays. 'right' will be null if sound is mono.
        public static void GetWaveData(byte[] wav, int channels, int sampleRate, int bitsPerSample, out float[] left, out float[] right)
        {
            int bytesPerSample = bitsPerSample / 8;
            int samples        = wav.Length / bytesPerSample / channels;

            // Allocate memory (right will be null if only mono sound)
            left  = new float[samples];
            right = (channels == 2) ? new float[samples] : null;
            // Write to float array/s:
            var subchunk2Size = wav.Length;
            var pos           = 0;
            int i             = 0;

            while (pos < subchunk2Size)
            {
                if (bytesPerSample == 1)
                {
                    left[i] = AudioHelper.BytesToNormalized_8(wav[pos]);
                    pos    += 1;
                    if (channels == 2)
                    {
                        right[i] = AudioHelper.BytesToNormalized_8(wav[pos]);
                        pos     += 1;
                    }
                    i++;
                }
                else
                {
                    left[i] = AudioHelper.BytesToNormalized_16(wav[pos], wav[pos + 1]);
                    pos    += 2;
                    if (channels == 2)
                    {
                        right[i] = AudioHelper.BytesToNormalized_16(wav[pos], wav[pos + 1]);
                        pos     += 2;
                    }
                    i++;
                }
            }
        }
コード例 #5
0
        // Return byte data from left and right float data. Ignore right when sound is mono
        public static void GetWaveData(float[] left, float[] right, ref byte[] data, int bitsPerSample)
        {
            int bytesPerSample = bitsPerSample / 8;
            // Calculate k
            // This value will be used to convert float to Int16
            // We are not using Int16.Max to avoid peaks due to overflow conversions
            float k = (bytesPerSample == 1)
                                ? (float)sbyte.MaxValue / left.Select(x => Math.Abs(x)).Max()
                                : (float)short.MaxValue / left.Select(x => Math.Abs(x)).Max();

            // Revert data to byte format
            Array.Clear(data, 0, data.Length);
            int dataLenght = left.Length;

            using (BinaryWriter writer = new BinaryWriter(new MemoryStream(data)))
            {
                for (int i = 0; i < dataLenght; i++)
                {
                    if (bytesPerSample == 1)
                    {
                        AudioHelper.Write8bit(writer, left[i], k);
                        if (right != null)
                        {
                            AudioHelper.Write8bit(writer, right[i], k);
                        }
                    }
                    else
                    {
                        AudioHelper.Write16bit(writer, left[i], k);
                        if (right != null)
                        {
                            AudioHelper.Write16bit(writer, right[i], k);
                        }
                    }
                }
            }
        }
コード例 #6
0
        /// <summary>
        /// Thread which will process all play items and convert XML to WAV bytes.
        /// </summary>
        /// <param name="status"></param>
        static void ProcessPlayItems(object status)
        {
            while (true)
            {
                PlayItem item = null;
                lock (threadIsRunningLock)
                {
                    lock (playlistLock)
                    {
                        // Get first incomplete item in the list.
                        JobStatusType[] validStates = { JobStatusType.Parsed, JobStatusType.Synthesized };
                        item = playlist.FirstOrDefault(x => validStates.Contains(x.Status));
                        // If nothing to do then...
                        if (item == null || playlist.Any(x => x.Status == JobStatusType.Error))
                        {
                            // Exit thread.
                            threadIsRunning = false;
                            return;
                        }
                    }
                }
                try
                {
                    // If XML is available.
                    if (item.Status == JobStatusType.Parsed)
                    {
                        item.Status = JobStatusType.Synthesizing;
                        var      encoding   = System.Text.Encoding.UTF8;
                        var      synthesize = true;
                        FileInfo xmlFi      = null;
                        FileInfo wavFi      = null;
                        if (SettingsManager.Options.CacheDataRead)
                        {
                            var dir = MainHelper.GetCreateCacheFolder();

                            // Look for generalized file first.
                            var uniqueName = item.GetUniqueFilePath(true);
                            // Get XML file path.
                            var xmlFile     = string.Format("{0}.xml", uniqueName);
                            var xmlFullPath = Path.Combine(dir.FullName, xmlFile);
                            xmlFi = new FileInfo(xmlFullPath);
                            // If generalized file do not exists then...
                            if (!xmlFi.Exists)
                            {
                                // Look for normal file.
                                uniqueName = item.GetUniqueFilePath(false);
                                // Get XML file path.
                                xmlFile     = string.Format("{0}.xml", uniqueName);
                                xmlFullPath = Path.Combine(dir.FullName, xmlFile);
                                xmlFi       = new FileInfo(xmlFullPath);
                            }
                            // Prefer MP3 audio file first (custom recorded file).
                            var wavFile     = string.Format("{0}.mp3", uniqueName);
                            var wavFullPath = Path.Combine(dir.FullName, wavFile);
                            wavFi = new FileInfo(wavFullPath);
                            // If wav do not exist or file is invalid.
                            if (!wavFi.Exists || wavFi.Length == 0)
                            {
                                // Get WAV file path.
                                wavFile     = string.Format("{0}.wav", uniqueName);
                                wavFullPath = Path.Combine(dir.FullName, wavFile);
                                wavFi       = new FileInfo(wavFullPath);
                            }
                            // If both files exists and Wav file is valid then...
                            if (xmlFi.Exists && wavFi.Exists && wavFi.Length > 0)
                            {
                                using (Stream stream = new FileStream(wavFi.FullName, FileMode.Open, FileAccess.Read))
                                {
                                    // Load existing XML and WAV data into PlayItem.
                                    var ms         = new MemoryStream();
                                    var ad         = new SharpDX.MediaFoundation.AudioDecoder(stream);
                                    var samples    = ad.GetSamples();
                                    var enumerator = samples.GetEnumerator();
                                    while (enumerator.MoveNext())
                                    {
                                        var sample = enumerator.Current.ToArray();
                                        ms.Write(sample, 0, sample.Length);
                                    }
                                    // Read WAV head.
                                    item.WavHead = ad.WaveFormat;
                                    // Read WAV data.
                                    item.WavData  = ms.ToArray();
                                    item.Duration = (int)ad.Duration.TotalMilliseconds;
                                }
                                // Load XML.
                                item.Xml = System.IO.File.ReadAllText(xmlFi.FullName);
                                // Make sure WAV data is not synthesized.
                                synthesize = false;
                            }
                        }
                        if (synthesize)
                        {
                            item.WavHead = new SharpDX.Multimedia.WaveFormat(
                                SettingsManager.Options.AudioSampleRate,
                                SettingsManager.Options.AudioBitsPerSample,
                                (int)SettingsManager.Options.AudioChannels);
                            // WavHead could change.
                            ConvertXmlToWav(item);
                        }
                        if (item.WavData != null)
                        {
                            var applyRate   = SettingsManager.Options.ModifyLocallyRate && _Rate != 0;
                            var applyPitch  = SettingsManager.Options.ModifyLocallyPitch && _Pitch != 0;
                            var applyVolume = SettingsManager.Options.ModifyLocallyVolume && item.Volume < 100;
                            if (applyRate || applyPitch)
                            {
                                var parameters = new SoundStretch.RunParameters();
                                parameters.TempoDelta = GetTempoDeltaFromRate(_Rate);
                                parameters.PitchDelta = (float)_Pitch;
                                parameters.Speech     = true;
                                var inStream = new MemoryStream();
                                AudioHelper.Write(item, inStream);
                                inStream.Position = 0;
                                var outStream = new MemoryStream();
                                SoundStretch.SoundTouchHelper.Process(inStream, outStream, parameters);
                                var outBytes = outStream.ToArray();
                                var pi       = DecodeToPlayItem(outBytes);
                                item.WavHead  = pi.WavHead;
                                item.WavData  = pi.WavData;
                                item.Duration = pi.Duration;
                                pi.Dispose();
                                inStream.Dispose();
                                outStream.Dispose();
                            }
                            if (applyVolume)
                            {
                                var inStream = new MemoryStream();
                                AudioHelper.Write(item, inStream);
                                inStream.Position = 0;
                                var vol       = (float)item.Volume / 100f;
                                var outStream = new MemoryStream();
                                AudioHelper.ChangeVolume(vol, inStream, outStream);
                                var outBytes = outStream.ToArray();
                                var pi       = DecodeToPlayItem(outBytes);
                                item.WavHead  = pi.WavHead;
                                item.WavData  = pi.WavData;
                                item.Duration = pi.Duration;
                                pi.Dispose();
                                inStream.Dispose();
                                outStream.Dispose();
                            }
                            if (SettingsManager.Options.CacheDataWrite || SettingsManager.Options.CacheAudioConvert)
                            {
                                // Create directory if not exists.
                                if (!xmlFi.Directory.Exists)
                                {
                                    xmlFi.Directory.Create();
                                }
                                if (!xmlFi.Exists)
                                {
                                    // Write XML.
                                    System.IO.File.WriteAllText(xmlFi.FullName, item.Xml, encoding);
                                }
                            }
                            // If data was synthesized i.e. was not loaded from the file then...
                            if (synthesize && SettingsManager.Options.CacheDataWrite)
                            {
                                AudioHelper.Write(item, wavFi);
                            }
                            // If must convert data to other formats.
                            if (SettingsManager.Options.CacheAudioConvert)
                            {
                                AudioHelper.Convert(item, wavFi);
                            }
                        }
                        item.Status = (item.WavHead == null || item.WavData == null)
                                                        ? item.Status = JobStatusType.Error
                                                        : item.Status = JobStatusType.Synthesized;
                    }
                    if (item.Status == JobStatusType.Synthesized)
                    {
                        item.Status = JobStatusType.Pitching;
                        ApplyPitch(item);
                        item.Status = JobStatusType.Pitched;
                    }
                }
                catch (Exception ex)
                {
                    OnEvent(Exception, ex);
                    item.Status = JobStatusType.Error;
                    // Exit thread.
                    threadIsRunning = false;
                    return;
                }
            }
        }