コード例 #1
0
ファイル: MainWindow.xaml.cs プロジェクト: VoidXH/Cavern
        void ProcessCommon(AudioReader reader, ref float[] impulse)
        {
            int targetLen = QMath.Base2Ceil((int)reader.Length) << 1;

            Complex[] commonSpectrum = new Complex[targetLen];
            FFTCache  cache          = new FFTCache(targetLen);

            for (int ch = 0; ch < reader.ChannelCount; ++ch)
            {
                float[] channel = new float[targetLen];
                WaveformUtils.ExtractChannel(impulse, channel, ch, reader.ChannelCount);

                Complex[] spectrum = Measurements.FFT(channel, cache);
                for (int band = 0; band < spectrum.Length; ++band)
                {
                    commonSpectrum[band] += spectrum[band];
                }
            }

            float mul = 1f / reader.ChannelCount;

            for (int band = 0; band < commonSpectrum.Length; ++band)
            {
                commonSpectrum[band] = (commonSpectrum[band] * mul).Invert();
            }

            Array.Resize(ref impulse, impulse.Length << 1);
            for (int ch = 0; ch < reader.ChannelCount; ++ch)
            {
                Convolver filter = GetFilter(commonSpectrum, 1, reader.SampleRate);
                filter.Process(impulse, ch, reader.ChannelCount);
            }
        }
コード例 #2
0
ファイル: MainWindow.xaml.cs プロジェクト: VoidXH/Cavern
        void ProcessPerChannel(AudioReader reader, ref float[] impulse)
        {
            int targetLen = QMath.Base2Ceil((int)reader.Length) << 1;

            Convolver[] filters = new Convolver[reader.ChannelCount];
            FFTCache    cache   = new FFTCache(targetLen);

            for (int ch = 0; ch < reader.ChannelCount; ++ch)
            {
                float[] channel = new float[targetLen];
                WaveformUtils.ExtractChannel(impulse, channel, ch, reader.ChannelCount);

                Complex[] spectrum = Measurements.FFT(channel, cache);
                for (int band = 0; band < spectrum.Length; ++band)
                {
                    spectrum[band] = spectrum[band].Invert();
                }
                filters[ch] = GetFilter(spectrum, WaveformUtils.GetRMS(channel), reader.SampleRate);
            }

            Array.Resize(ref impulse, impulse.Length << 1);
            for (int ch = 0; ch < reader.ChannelCount; ++ch)
            {
                filters[ch].Process(impulse, ch, reader.ChannelCount);
            }
        }
コード例 #3
0
 /// <summary>
 /// Convert a float array to complex a size that's ready for FFT.
 /// </summary>
 public static Complex[] ParseForFFT(this float[] source)
 {
     Complex[] result = new Complex[QMath.Base2Ceil(source.Length)];
     for (int i = 0; i < source.Length; ++i)
     {
         result[i].Real = source[i];
     }
     return(result);
 }
コード例 #4
0
ファイル: MainWindow.xaml.cs プロジェクト: VoidXH/Cavern
        void ProcessImpulse(object sender, RoutedEventArgs e)
        {
            if (browser.ShowDialog().Value)
            {
                AudioReader reader  = AudioReader.Open(browser.FileName);
                float[]     impulse = reader.Read();
                float       gain    = 1;
                if (keepGain.IsChecked.Value)
                {
                    gain = WaveformUtils.GetPeak(impulse);
                }

                if (commonEQ.IsChecked.Value)
                {
                    ProcessCommon(reader, ref impulse);
                }
                else
                {
                    ProcessPerChannel(reader, ref impulse);
                }

                if (keepGain.IsChecked.Value)
                {
                    WaveformUtils.Gain(impulse, gain / WaveformUtils.GetPeak(impulse));
                }

                BitDepth bits = reader.Bits;
                if (forceFloat.IsChecked.Value)
                {
                    bits = BitDepth.Float32;
                }

                int targetLen = QMath.Base2Ceil((int)reader.Length);
                if (separateExport.IsChecked.Value)
                {
                    ReferenceChannel[] channels = ChannelPrototype.GetStandardMatrix(reader.ChannelCount);
                    for (int ch = 0; ch < reader.ChannelCount; ++ch)
                    {
                        string exportName  = Path.GetFileName(browser.FileName);
                        int    idx         = exportName.LastIndexOf('.');
                        string channelName = ChannelPrototype.Mapping[(int)channels[ch]].Name;
                        exporter.FileName = $"{exportName[..idx]} - {channelName}{exportName[idx..]}";
コード例 #5
0
        private void LoadFiles(object sender, RoutedEventArgs e)
        {
            AudioReader responseReader = Import("Response.wav");

            if (responseReader == null)
            {
                return;
            }
            AudioReader impulseReader = Import("Impulse.wav");

            if (impulseReader == null)
            {
                return;
            }

            float[] response = responseReader.Read(),
            impulse = impulseReader.Read();
            if (responseReader.SampleRate != impulseReader.SampleRate)
            {
                Error("The sample rate of the two clips don't match.");
                return;
            }
            int responseChannels = responseReader.ChannelCount,
                impulseChannels  = impulseReader.ChannelCount;

            if (impulseChannels != 1 && impulseChannels != responseChannels)
            {
                Error("The channel count of the two clips don't match. A single-channel impulse is also acceptable.");
                return;
            }

            int fftSize = Math.Max(
                QMath.Base2Ceil((int)responseReader.Length),
                QMath.Base2Ceil((int)impulseReader.Length)
                );

            if (padding.IsChecked.Value)
            {
                Array.Resize(ref response, fftSize + response.Length);
                Array.Copy(response, 0, response, fftSize, response.Length - fftSize);
                Array.Clear(response, 0, fftSize);

                fftSize = Math.Max(fftSize, QMath.Base2Ceil(response.Length));
            }

            Complex[] impulseFFT = new Complex[fftSize],
            responseFFT = new Complex[fftSize];
            FFTCache cache = new FFTCache(fftSize);

            float[] responseChannel = new float[response.Length / responseChannels];
            for (int channel = 0; channel < responseChannels; ++channel)
            {
                if (channel < impulseChannels)   // After the channel count check this runs once or for each channel
                {
                    float[] impulseChannel = impulse;
                    if (impulseChannels != 1)
                    {
                        impulseChannel = new float[impulseReader.Length];
                        WaveformUtils.ExtractChannel(impulse, impulseChannel, channel, impulseChannels);
                        Array.Clear(impulseFFT, 0, fftSize);
                    }
                    for (int sample = 0; sample < impulseChannel.Length; ++sample)
                    {
                        impulseFFT[sample].Real = impulseChannel[sample];
                    }
                    Measurements.InPlaceFFT(impulseFFT, cache);
                }

                if (responseChannels == 1)
                {
                    responseChannel = response;
                }
                else
                {
                    WaveformUtils.ExtractChannel(response, responseChannel, channel, responseChannels);
                }
                if (channel != 1)
                {
                    Array.Clear(responseFFT, 0, fftSize);
                }
                for (int sample = 0; sample < responseChannel.Length; ++sample)
                {
                    responseFFT[sample].Real = responseChannel[sample];
                }
                Measurements.InPlaceFFT(responseFFT, cache);

                for (int sample = 0; sample < fftSize; ++sample)
                {
                    responseFFT[sample].Divide(impulseFFT[sample]);
                }
                Measurements.InPlaceIFFT(responseFFT, cache);
                for (int i = 0, channels = responseChannels; i < responseChannel.Length; ++i)
                {
                    response[channels * i + channel] = responseFFT[i].Real;
                }
            }

            exporter.FileName = "Deconvolved.wav";
            if (exporter.ShowDialog().Value)
            {
                BinaryWriter handler = new BinaryWriter(File.OpenWrite(exporter.FileName));
                using RIFFWaveWriter writer = new RIFFWaveWriter(handler, responseChannels, responseReader.Length,
                                                                 responseReader.SampleRate, responseReader.Bits);
                writer.Write(response);
            }
        }