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; }
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; }
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; }