static void WriteImpulsePCM(ISoundObj stereoImpulse, string fileNameL, string fileNameR)
        {
            ISoundObj sb;
            WaveWriter writer;
            ushort bits = 32;
            int nTot = 196607;
            int nBef = 98300;

            // need padding before the sample.
            // window the sample first, then pad it.
            // Total length 65536, includes nPad and _peakPosL before impulse
            int nPad = nBef - _peakPosL;
            int usableLength = nTot - nPad;
            int windowCenter = usableLength / 2;
            int windowSide = _peakPosL * 2 / 3;
            int windowFlat = windowCenter - windowSide;
            ISoundObj ch = new SingleChannel(stereoImpulse, 0);
            ISoundObj wn = new BlackmanHarris(windowCenter, windowSide, windowFlat);
            wn.Input = ch;
            sb = new SampleBuffer(wn).PaddedSubset(-nPad, nTot);

            writer = new WaveWriter(fileNameL);
            writer.Input = sb;
            writer.Format = WaveFormat.IEEE_FLOAT;
            writer.BitsPerSample = bits;
            writer.SampleRate = _sampleRate;
            writer.Raw = true;

            writer.Normalization = -6.0;
            writer.NormalizationType = NormalizationType.PEAK_DBFS;

            writer.Run();
            writer.Close();

            double g = writer.Gain;

            writer = null;

            nPad = nBef - _peakPosR;
            usableLength = nTot - nPad;
            windowCenter = usableLength / 2;
            windowSide = _peakPosR * 2 / 3;
            windowFlat = windowCenter - windowSide;
            ch = new SingleChannel(stereoImpulse, 1);
            wn = new BlackmanHarris(windowCenter, windowSide, windowFlat);
            wn.Input = ch;
            sb = new SampleBuffer(wn).PaddedSubset(-nPad, nTot);

            writer = new WaveWriter(fileNameR);
            writer.Input = sb;
            writer.Format = WaveFormat.IEEE_FLOAT;
            writer.BitsPerSample = bits;
            writer.SampleRate = _sampleRate;
            writer.Raw = true;
            writer.Gain = g;
            writer.Run();
            writer.Close();
            writer = null;
        }
Exemple #2
0
        static ISoundObj GetSignalGenerator(double dBfs, out string desc)
        {
            double gain = MathUtil.gain(dBfs);
            ISoundObj signalGenerator = null;
            Sequencer seq;
            string description = "Unknown";
            switch (_siggen)
            {
                case "IDENT":
                    // Left-right identification: embedded resource
                    Assembly ass = Assembly.GetExecutingAssembly();
                    foreach (string s in ass.GetManifestResourceNames())
                    {
                        if (s.Contains("LeftRight"))
                        {
                            Stream res = ass.GetManifestResourceStream(s);
                            WaveReader rdr = new WaveReader(res);
                            // The stream is stereo, but we want to alternate
                            seq = new Sequencer();

                            for (int j = 0; j < 10; j++)
                            {
                                seq.Add(rdr, new List<double>(new double[] { gain, 0 }));
                                seq.Add(new NoiseGenerator(NoiseType.SILENCE, 2, 1.0, _inputSampleRate, 0.0, false));
                                seq.Add(rdr, new List<double>(new double[] { 0, gain }));
                                seq.Add(new NoiseGenerator(NoiseType.SILENCE, 2, 1.0, _inputSampleRate, 0.0, false));
                            }

                            signalGenerator = seq;
                            break;
                        }
                    }
                    /*
                    // Left-right identification signal: morse code
                    MorseCode envL = new MorseCode(" " + _sigparamA, 10, true);
                    ISoundObj sigL = new SweepGenerator(1, envL.LengthSeconds * 5, 220, 7040, _inputSampleRate, 0, false, gain, true);
                    envL.Input = sigL;

                    MorseCode envR = new MorseCode(" " + _sigparamB, 10, true);
                    ISoundObj sigR = new SweepGenerator(1, envR.LengthSeconds * 5, 7040, 220, _inputSampleRate, 0, false, gain, true);
                    envR.Input = sigR;

                    signalGenerator = new ChannelSplicer();
                    (signalGenerator as ChannelSplicer).Add(envL);
                    (signalGenerator as ChannelSplicer).Add(envR);
                    */
                    description = String.Format("Left/Right channel identification");
                    break;

                case "SWEEP":
                    seq = new Sequencer();
                    if (_sigparam1 == 0)
                    {
                        _sigparam1 = 45;
                    }
                    int lengthSamples = (int)(_sigparam1 * _inputSampleRate);
                    if (lengthSamples < 8388608)
                    {
                        // High-accuracy logarithmic sweep starting at 10Hz
                        int fade = (int)(_inputSampleRate / 20);
                        FFTSweepGenerator sg = new FFTSweepGenerator(2, lengthSamples, 10, _inputSampleRate / 2, _inputSampleRate, gain, false);
                        seq.Add(sg);
                        description = String.Format("Logarithmic sine sweep 10Hz to {0}Hz in {1} seconds", _inputSampleRate / 2, _sigparam1);
                    }
                    else
                    {
                        // Simple logarithmic sweep starting at 10Hz, windowed (uses much less memory!)
                        int fade = (int)(_inputSampleRate / 20);
                        BlackmanHarris bhwf = new BlackmanHarris(lengthSamples / 2, fade, (int)((lengthSamples / 2) - fade));
                        SweepGenerator sg = new SweepGenerator(2, lengthSamples, 10, _inputSampleRate / 2, _inputSampleRate, gain, false);
                        bhwf.Input = sg;
                        seq.Add(bhwf);
                        description = String.Format("Log sine sweep 10Hz to {0}Hz in {1} seconds", _inputSampleRate / 2, _sigparam1);
                    }
                    // Follow by 3 seconds of silence
                    seq.Add(new NoiseGenerator(NoiseType.SILENCE, 2, 3.0, _inputSampleRate, 0.0, false));
                    signalGenerator = seq;
                    break;

                case "SINE":
                    signalGenerator = new SineGenerator(2, _inputSampleRate, _sigparam1, gain);
                    description = String.Format("{0}Hz sine", _sigparam1);
                    break;

                case "QUAD":
                    signalGenerator = new SineQuadGenerator(2, _inputSampleRate, _sigparam1, gain);
                    description = String.Format("{0}Hz quadrature", _sigparam1);
                    break;

                case "SQUARE":
                    signalGenerator = new SquareGenerator(2, _inputSampleRate, _sigparam1, gain);
                    description = String.Format("{0}Hz non-bandlimited square", _sigparam1);
                    break;

                case "BLSQUARE":
                    signalGenerator = new BandLimitedSquareGenerator(2, _inputSampleRate, _sigparam1, gain);
                    description = String.Format("{0}Hz bandlimited square", _sigparam1);
                    break;

                case "TRIANGLE":
                    signalGenerator = new TriangleGenerator(2, _inputSampleRate, _sigparam1, gain);
                    description = String.Format("{0}Hz non-bandlimited triangle", _sigparam1);
                    break;

                case "BLTRIANGLE":
                    signalGenerator = new BandLimitedTriangleGenerator(2, _inputSampleRate, _sigparam1, gain);
                    description = String.Format("{0}Hz bandlimited triangle", _sigparam1);
                    break;

                case "SAWTOOTH":
                    signalGenerator = new SawtoothGenerator(2, _inputSampleRate, _sigparam1, gain);
                    description = String.Format("{0}Hz non-bandlimited sawtooth", _sigparam1);
                    break;

                case "BLSAWTOOTH":
                    signalGenerator = new BandLimitedSawtoothGenerator(2, _inputSampleRate, _sigparam1, gain);
                    description = String.Format("{0}Hz bandlimited sawtooth", _sigparam1);
                    break;

                case "WHITE":
                    signalGenerator = new NoiseGenerator(NoiseType.WHITE, 2, int.MaxValue, _inputSampleRate, gain, true);
                    description = String.Format("White noise");
                    break;

                case "PINK":
                    bool mono = (_sigparam1 != 0 ? true : false);
                    signalGenerator = new NoiseGenerator(NoiseType.PINK, 2, int.MaxValue, _inputSampleRate, gain, mono);
                    description = String.Format("Pink noise {0}", mono ? "(mono)" : "(stereo)" );
                    break;

                case "INTERMODULATION":
                    double n = 1;
                    description = String.Format("Intermodulation test {0}Hz", _sigparam1);
                    if (_sigparam2 != 0) { n++; description = description + " + " + _sigparam2 + "Hz"; }
                    if (_sigparam3 != 0) { n++; description = description + " + " + _sigparam3 + "Hz"; }
                    signalGenerator = new Mixer();
                    (signalGenerator as Mixer).Add(new SineGenerator(2, _inputSampleRate, _sigparam1, gain), 1/n);
                    if (_sigparam2 != 0) (signalGenerator as Mixer).Add(new SineGenerator(2, _inputSampleRate, _sigparam2, gain), 1 / n);
                    if (_sigparam3 != 0) (signalGenerator as Mixer).Add(new SineGenerator(2, _inputSampleRate, _sigparam3, gain), 1 / n);
                    break;

                case "SHAPEDBURST":
                    description = String.Format("{0}Hz windowed (Blackman) over {1} cycles", _sigparam1, _sigparam2);
                    throw new NotImplementedException();
                    //break;

                default:
                    _siggen = null;
                    break;
            }
            if (IsSigGenEQ())
            {
                if (IsSigGenEQBoth())
                {
                    description = description + ", with EQ processing";
                }
                else if (IsSigGenEQL())
                {
                    description = description + ", with EQ processing in left channel";
                }
                else if (IsSigGenEQR())
                {
                    description = description + ", with EQ processing in right channel";
                }
                else
                {
                    description = description + ", with EQ processing";
                }
            }
            desc = description;
            return signalGenerator;
        }
        static ISoundObj Splice(string infileL, int peakPosL, string infileR, int peakPosR, string outfile)
        {
            //int tmp1;
            //bool tmp2;
            WaveReader reader1 = new WaveReader(infileL, WaveFormat.IEEE_FLOAT, 32, 1);
            //            reader1.Skip(peakPosL, out tmp1, out tmp2);
            SoundBuffer buff1 = new SoundBuffer(reader1);
            buff1.ReadAll();

            // Normalize loudness for each channel
            double g = Loudness.WeightedVolume(buff1);
            buff1.ApplyGain(1/g);

            WaveReader reader2 = new WaveReader(infileR, WaveFormat.IEEE_FLOAT, 32, 1);
            //            reader2.Skip(peakPosR, out tmp1, out tmp2);
            SoundBuffer buff2 = new SoundBuffer(reader2);
            buff2.ReadAll();

            g = Loudness.WeightedVolume(buff2);
            buff2.ApplyGain(1/g);

            ChannelSplicer splicer = new ChannelSplicer();
            splicer.Add(buff1);
            splicer.Add(buff2);

            // General-purpose:
            // Find the extremities of the DRC impulse,
            // window asymmetrically.
            //
            // But, since we specifically used linear-phase filters on target and mic,
            // we know that the impulse is centered.
            // We want an impulse length (_filterLen)
            // so window the 2048 samples at each end (which are pretty low to begin with - less than -100dB)

            ISoundObj output;
            int nCount = (int)(buff1.Count / 2);
            if (nCount > _filterLen/2)
            {
                BlackmanHarris bhw = new BlackmanHarris(nCount, 2048, (nCount / 2) - 2048);
                bhw.Input = splicer;
                SampleBuffer sb = new SampleBuffer(bhw);
                output = sb.Subset(_filterLen/2, _filterLen);
            }
            else
            {
                output = splicer;
            }

            ISoundObj result = output;
            if (!_noSkew)
            {
                // Apply skew to compensate for time alignment in the impulse responses
                Skewer skewer = new Skewer(true);
                skewer.Input = output;
                skewer.Skew = peakPosL - peakPosR;
                result = skewer;
            }

            WaveWriter writer = new WaveWriter(outfile);
            writer.Input = result;
            writer.Dither = DitherType.NONE;
            writer.Format = WaveFormat.IEEE_FLOAT;
            writer.BitsPerSample = 32;
            writer.SampleRate = _sampleRate;
            writer.NumChannels = splicer.NumChannels;
            if (Double.IsNaN(_gain))
            {
                writer.Normalization = 0;
            }
            else
            {
                writer.Gain = MathUtil.gain(_gain);
            }
            writer.Run();
            writer.Close();
            reader1.Close();
            reader2.Close();

            return result;
        }
Exemple #4
0
        static SoundObj GetMainImpulse(out string actualPath)
        {
            DateTime dtStart = DateTime.Now;
            if (_impulsePath == "") _impulsePath = null;
            if (_impulsePath == "-") _impulsePath = null;
            if (_matrixFilter == "") _matrixFilter = null;
            if (_matrixFilter == "-") _matrixFilter = null;
            if (_bformatFilter == "") _bformatFilter = null;
            if (_bformatFilter == "-") _bformatFilter = null;
            Trace.WriteLine("Impulse {0}, matrix {1}", CleanPath(_dataFolder, _impulsePath), CleanPath(_dataFolder, _matrixFilter));

            // note: we window the room correction impulse if it's too long
            WaveReader impulseReader = null;
            SoundObj impulseObj = null;
            actualPath = null;

            if (!String.IsNullOrEmpty(_impulsePath))
            {
                impulseReader = GetAppropriateImpulseReader(_impulsePath, out actualPath);
            }
            if (impulseReader != null)
            {
                if (impulseReader.Iterations > _maxImpulseLength)
                {
                    // This impulse is too long.
                    // Trim it to length.
                    int hwid = _maxImpulseLength / 2;
                    int qwid = _maxImpulseLength / 4;
                    SoundBuffer buff = new SoundBuffer(impulseReader);
                    buff.ReadAll();
                    int center = buff.MaxPos();
                    BlackmanHarris wind;
                    int startpos;
                    if (center < hwid)
                    {
                        wind = new BlackmanHarris(center, qwid, qwid);
                        startpos = 0;
                    }
                    else
                    {
                        wind = new BlackmanHarris(hwid, qwid, qwid);
                        startpos = center - hwid;
                    }
                    //                        int startpos = center < hwid ? 0 : (center - hwid);
                    wind.Input = buff.Subset(startpos, _maxImpulseLength);
                    impulseObj = wind;
                }
                else
                {
                    impulseObj = impulseReader;
                }
            }

            if (_debug)
            {
                TimeSpan ts = DateTime.Now.Subtract(dtStart);
                Trace.WriteLine("GetMainImpulse " + ts.TotalMilliseconds);
            }
            return impulseObj;
        }