예제 #1
0
        public ConvertingSampleProvider(IWaveProvider waveProvider, WaveFormat targetFormat)
        {
            if (waveProvider.WaveFormat.SampleRate != targetFormat.SampleRate)
            {
                if (waveProvider.WaveFormat.Encoding == WaveFormatEncoding.IeeeFloat)
                {
                    provider = ((resampler = new MediaFoundationResampler(waveProvider, targetFormat)) as MediaFoundationResampler).ToSampleProvider();
                }
                else
                {
                    provider = ((resampler = new MediaFoundationResampler(new Wave16ToFloatProvider(waveProvider), targetFormat)) as MediaFoundationResampler).ToSampleProvider();
                }
            }
            else
            {
                provider = waveProvider.ToSampleProvider();
            }

            if (provider.WaveFormat.Channels != targetFormat.Channels)
            {
                if (targetFormat.Channels == 1 & provider.WaveFormat.Channels > 1)
                {
                    provider = provider.ToMono();
                }
                else if (targetFormat.Channels == 2)
                {
                    provider = provider.ToStereo();
                }
                else
                {
                    throw new InvalidWaveFormatException($"Couldn´t find a suitable conversion from {provider.WaveFormat.Channels} to {targetFormat.Channels} Channels");
                }
            }
        }
예제 #2
0
 public ISampleProvider SupplySample(bool stereo, bool loop, ISampleProvider input)
 {
     if (stereo)
     {
         input.ToStereo();
     }
     else
     {
         input.ToMono();
     }
     return(input);
 }
예제 #3
0
            public SampleProvider(string folderPath, ISampleProvider input, SourceLocation location)
            {
                this.hrtf = new HRTF(folderPath);
                this.hrtf.Init();
                this.binSyn   = new BinauralSynthesis(currInput, dataOutput);
                this.location = location;

                // convert stereo input to mono
                if (input.WaveFormat.Channels != 1)
                {
                    this.input = input.ToMono();
                }
                else
                {
                    this.input = input;
                }

                WaveFormat = input.ToStereo().WaveFormat;
            }
예제 #4
0
        public async ValueTask <VoiceAnalysisResult> Analyze(VowelClassifierType classifierType, ISampleProvider provider)
        {
            // TODO: あまりにも無駄な再計算が多い & 並列化しろ

            const int vowelWindowSize = 2048;
            const int pitchWindowSize = 1024;

            provider = provider.ToMono();
            var sampleRate = provider.WaveFormat.SampleRate;

            var blocks = new List <NoteBlockModel>();

            var classifier = await this._vowelClassifierTasks[classifierType].ConfigureAwait(false);
            var samples    = new float[Logics.AnalysisUnit];

            for (var unitCount = 0; ; unitCount++)
            {
                // 4096 サンプルを読み込み
                for (var readSamples = 0; readSamples < samples.Length;)
                {
                    var count = provider.Read(samples, readSamples, samples.Length - readSamples);
                    if (count == 0)
                    {
                        return(new VoiceAnalysisResult(blocks.ToImmutableArray(), unitCount));
                    }
                    readSamples += count;
                }

                var maxPower = 0f;
                foreach (var x in samples)
                {
                    if (x > maxPower)
                    {
                        maxPower = x;
                    }
                }

                // 音量小さすぎ
                if (maxPower < 0.15)
                {
                    continue;
                }

                // 512 ずつずらしながら母音認識
                var vowelCandidates = new int[(int)VowelType.Other + 1];
                for (var offset = 0; offset <= Logics.AnalysisUnit - vowelWindowSize; offset += 512)
                {
                    vowelCandidates[(int)classifier.Decide(new ReadOnlySpan <float>(samples, offset, vowelWindowSize), sampleRate)]++;
                }

                var vowelCandidate = default(VowelType?);
                var maxNumOfVotes  = 0;
                for (var j = 0; j < vowelCandidates.Length; j++)
                {
                    if (vowelCandidates[j] > maxNumOfVotes)
                    {
                        maxNumOfVotes  = vowelCandidates[j];
                        vowelCandidate = (VowelType)j;
                    }
                    else if (vowelCandidates[j] == maxNumOfVotes)
                    {
                        vowelCandidate = null;
                    }
                }

                // 母音が定まらなかったので、終了
                if (!vowelCandidate.HasValue || vowelCandidate.Value == VowelType.Other)
                {
                    continue;
                }

                // 512 ずつずらしながらピッチ検出
                const int pitchOffsetDelta = 512;
                var       basicFreqs       = new List <double>((Logics.AnalysisUnit - pitchOffsetDelta) / pitchOffsetDelta);
                for (var offset = 0; offset <= Logics.AnalysisUnit - pitchWindowSize; offset += pitchOffsetDelta)
                {
                    var f = McLeodPitchMethod.EstimateFundamentalFrequency(
                        sampleRate,
                        new ReadOnlySpan <float>(samples, offset, pitchWindowSize)
                        );

                    if (f.HasValue)
                    {
                        basicFreqs.Add(f.Value);
                    }
                }

                // ピッチ検出に失敗したので終了
                if (basicFreqs.Count == 0)
                {
                    continue;
                }

                basicFreqs.Sort();
                var basicFreq = basicFreqs[basicFreqs.Count / 2]; // 中央値
                var noteNum   = CommonUtils.HzToMidiNote(basicFreq);

                var block = new NoteBlockModel(unitCount, noteNum, vowelCandidate.Value);

                if (blocks.Count == 0 || !blocks[blocks.Count - 1].MergeIfPossible(block))
                {
                    blocks.Add(block);
                }
            }
        }