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"); } } }
public ISampleProvider SupplySample(bool stereo, bool loop, ISampleProvider input) { if (stereo) { input.ToStereo(); } else { input.ToMono(); } return(input); }
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; }
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); } } }