public static double getAvgAmplitude(WaveAudio w) { double total=0; for (int i=0; i<w.LengthInSamples; i++) total += w.data[0][i]*w.data[0][i]; return total/w.LengthInSamples; }
public static WaveAudio Modulate(WaveAudio w1, WaveAudio w2) { ElementWiseCombinationFn fn = delegate(double v1, double v2) { return v1 * v2; }; return elementWiseCombination(w1, w2, fn); }
public static WaveAudio Mix(WaveAudio w1, double weight1, WaveAudio w2, double weight2) { ElementWiseCombinationFn fn = delegate(double v1, double v2) { return weight1 * v1 + weight2 * v2; }; return elementWiseCombination(w1, w2, fn); }
public static void placeAudio(WaveAudio target, WaveAudio source, int index) { for (int ch=0; ch<target.data.Length; ch++) for (int j = 0; j < source.data[0].Length; j++) if (j + index < target.data[0].Length) { target.data[ch][j + index] += source.data[ch][j]; } }
public static WaveAudio Reverse(WaveAudio w1) { WaveAudio clone = w1.Clone(); for (int ch = 0; ch < clone.data.Length; ch++) { Array.Reverse( clone.data[ch]); } return clone; }
private void btnOpen_Click(object sender, EventArgs e) { string strFilename, strShortname; WaveAudio w; CommonWave.commonLoadWaveFile(out strFilename, out strShortname, out w); if (w==null) return; this.lblFilename.Text = "Loaded: " + strShortname; w.setNumChannels(1, true); //convert to mono this.m_currentSound = w; }
public static double getAvgAmplitude(WaveAudio w) { double total = 0; for (int i = 0; i < w.LengthInSamples; i++) { total += w.data[0][i] * w.data[0][i]; } return(total / w.LengthInSamples); }
public static WaveAudio Reverse(WaveAudio w1) { WaveAudio clone = w1.Clone(); for (int ch = 0; ch < clone.data.Length; ch++) { Array.Reverse(clone.data[ch]); } return(clone); }
/// <summary> /// Create deep copy of audio object. /// </summary> public WaveAudio Clone() { WaveAudio copy = new WaveAudio(this.getSampleRate(), this.getNumChannels()); for (int ch = 0; ch < copy.data.Length; ch++) { copy.data[ch] = new double[this.data[ch].Length]; Array.Copy(this.data[ch], copy.data[ch], this.data[ch].Length); } return(copy); }
/// <summary> /// Create a new sound by changing the speed/pitch of the old sound. 2.0 = an octave up, 1.0 = the same, 0.5 = down an octave /// </summary> public static WaveAudio ScalePitchAndDuration(WaveAudio w, double factor) { if (factor < 0) throw new ArgumentException("Factor must >= 0"); WaveAudio res = new WaveAudio(w.getSampleRate(), w.getNumChannels()); // do operation for all channels for (int i = 0; i < w.getNumChannels(); i++) res.data[i] = scalePitchAndDurationChannel(w.data[i], factor); return res; }
public static WaveAudio GetSliceSample(WaveAudio wthis, int nStart, int nEnd) { WaveAudio slice = new WaveAudio(wthis.getSampleRate(), wthis.getNumChannels()); if (nEnd <= nStart || nEnd > wthis.LengthInSamples || nStart < 0) throw new Exception("Invalid slice"); for (int ch = 0; ch < slice.data.Length; ch++) { slice.data[ch] = new double[nEnd - nStart]; Array.Copy(wthis.data[ch], nStart, slice.data[ch], 0, nEnd - nStart); } return slice; }
public static WaveAudio Vibrato(WaveAudio wave, double freq, double width) { if (width < 0) throw new ArgumentException("Factor must >= 0"); WaveAudio newwave = new WaveAudio(wave.getSampleRate(), wave.getNumChannels()); // do operation for all channels for (int i = 0; i < wave.getNumChannels(); i++) newwave.data[i] = vibratoChannel(wave.data[i], wave.getSampleRate(), width, freq); return newwave; }
public static WaveAudio hiPassFilter(WaveAudio w, double factor) //0.5 { WaveAudio ret = new WaveAudio(w.getSampleRate(), w.getNumChannels()); ret.LengthInSamples = w.LengthInSamples; for (int ch = 0; ch < w.getNumChannels(); ch++) { ret.data[ch][0] = w.data[ch][0]; for (int i = 1; i < ret.data[ch].Length; i++) ret.data[ch][i] = factor * ret.data[ch][i - 1] + (factor) * (w.data[ch][i] - w.data[ch][i-1]); } return ret; }
//could also get continuous with window. public static WaveAudio lowPassFilter(WaveAudio w, double factor) //0.5 { //http://en.wikipedia.org/wiki/Low-pass_filter WaveAudio ret = new WaveAudio(w.getSampleRate(), w.getNumChannels()); ret.LengthInSamples = w.LengthInSamples; for (int ch = 0; ch < w.getNumChannels(); ch++) { ret.data[ch][0] = w.data[ch][0]; for (int i=1; i<ret.data[ch].Length; i++) ret.data[ch][i] = (1-factor)*ret.data[ch][i-1] + (factor)*w.data[ch][i]; } return ret; }
public static void placeAudio(WaveAudio target, WaveAudio source, int index) { for (int ch = 0; ch < target.data.Length; ch++) { for (int j = 0; j < source.data[0].Length; j++) { if (j + index < target.data[0].Length) { target.data[ch][j + index] += source.data[ch][j]; } } } }
public static void placeAudioRamp(WaveAudio target, WaveAudio source, int index, int rampWidth) { for (int ch=0; ch<target.data.Length; ch++) for (int j = 0; j < source.data[ch].Length; j++) { if (j < rampWidth) target.data[ch][j + index] += source.data[ch][j] * (((double)j) / rampWidth); else if ((source.data[ch].Length - j) < rampWidth) target.data[ch][j + index] += source.data[ch][j] * (((double)source.data[ch].Length - j) / rampWidth); else target.data[ch][j + index] += source.data[ch][j]; } }
public void Play(WaveAudio a, bool bAsync) { m = new MemoryStream(); bw = new BinaryWriter(m); a.SaveWaveFile(bw); SoundPlayer pl = new SoundPlayer(m); pl.Stream.Position = 0; // This line is necessary if (bAsync) pl.Play(); else pl.PlaySync(); }
// These work by shifting the signal until it seems to correlate with itself. // In other words if the signal looks very similar to (signal shifted 200 samples) than the fundamental period is probably 200 samples // Note that the algorithm only works well when there's only one prominent fundamental. // This could be optimized by looking at the rate of change to determine a maximum without testing all periods. private static double[] detectPitchCalculation(WaveAudio w, double minHz, double maxHz, int nCandidates, int nResolution, PitchDetectAlgorithm algorithm) { // note that higher frequency means lower period int nLowPeriodInSamples = hzToPeriodInSamples(maxHz, w.getSampleRate()); int nHiPeriodInSamples = hzToPeriodInSamples(minHz, w.getSampleRate()); if (nHiPeriodInSamples <= nLowPeriodInSamples) throw new Exception("Bad range for pitch detection."); if (w.getNumChannels() != 1) throw new Exception("Only mono supported."); double[] samples = w.data[0]; if (samples.Length < nHiPeriodInSamples) throw new Exception("Not enough samples."); // both algorithms work in a similar way // they yield an array of data, and then we find the index at which the value is highest. double[] results = new double[nHiPeriodInSamples - nLowPeriodInSamples]; if (algorithm == PitchDetectAlgorithm.Amdf) { for (int period = nLowPeriodInSamples; period < nHiPeriodInSamples; period += nResolution) { double sum = 0; // for each sample, see how close it is to a sample n away. Then sum these. for (int i = 0; i < samples.Length - period; i++) sum += Math.Abs(samples[i] - samples[i + period]); double mean = sum / (double)samples.Length; mean *= -1; //somewhat of a hack. We are trying to find the minimum value, but our findBestCandidates finds the max. value. results[period - nLowPeriodInSamples] = mean; } } else if (algorithm == PitchDetectAlgorithm.Autocorrelation) { for (int period = nLowPeriodInSamples; period < nHiPeriodInSamples; period += nResolution) { double sum = 0; // for each sample, find correlation. (If they are far apart, small) for (int i = 0; i < samples.Length - period; i++) sum += samples[i] * samples[i + period]; double mean = sum / (double)samples.Length; results[period - nLowPeriodInSamples] = mean; } } // find the best indices int[] bestIndices = findBestCandidates(nCandidates, ref results); //note findBestCandidates modifies parameter // convert back to Hz double[] res = new double[nCandidates]; for (int i=0; i<nCandidates;i++) res[i] = periodInSamplesToHz(bestIndices[i]+nLowPeriodInSamples, w.getSampleRate()); return res; }
//get continuous value, with a window. the 'instantaneous amplitude' //note: only from 1st channel of audio. public static double[] getAmplitudesOverTimeContinuous(WaveAudio w, int nWindowSize) { double[] res = new double[w.LengthInSamples]; double current=0; for (int i=0; i<w.LengthInSamples; i++) { current += w.data[0][i]*w.data[0][i]; if (i>nWindowSize) current-= w.data[0][i-nWindowSize]*w.data[0][i-nWindowSize]; res[i] = current / nWindowSize; } return res; }
private static void commonSaveWaveFile(WaveAudio w) { string strFilename = getSaveFilename(); if (strFilename == null || strFilename == "") return; try { w.SaveWaveFile(strFilename); } catch (Exception er) { MessageBox.Show("Error when saving wave file: " + er.Message); return; } }
public static void effectstest(AudioPlayer pl) { WaveAudio w = new WaveAudio(mediadir + "d44k16bit2ch.wav"); pl.Play(Effects.Derivative(w)); pl.Play(Effects.Flange(w)); pl.Play(Effects.Reverse(w)); pl.Play(Effects.ScalePitchAndDuration(w, 0.75)); pl.Play(Effects.ScalePitchAndDuration(w, 1.25)); pl.Play(Effects.Tremolo(w, 1.0, 1.0)); pl.Play(Effects.Vibrato(w, 0.2, 0.5)); w.setSampleRate(22050); pl.Play(w); // should sound "normal" }
public static WaveAudio Derivative(WaveAudio wOriginal) { WaveAudio w = wOriginal.Clone(); for (int ch = 0; ch < w.getNumChannels(); ch++) { for (int i = 0; i < w.data[ch].Length; i++) { if (i + 1 < w.data[ch].Length) w.data[ch][i] = w.data[ch][i] - w.data[ch][i + 1]; else w.data[ch][i] = w.data[ch][i] - 0; } } return w; }
public static WaveAudio hiPassFilter(WaveAudio w, double factor) //0.5 { WaveAudio ret = new WaveAudio(w.getSampleRate(), w.getNumChannels()); ret.LengthInSamples = w.LengthInSamples; for (int ch = 0; ch < w.getNumChannels(); ch++) { ret.data[ch][0] = w.data[ch][0]; for (int i = 1; i < ret.data[ch].Length; i++) { ret.data[ch][i] = factor * ret.data[ch][i - 1] + (factor) * (w.data[ch][i] - w.data[ch][i - 1]); } } return(ret); }
public static WaveAudio GetSliceSample(WaveAudio wthis, int nStart, int nEnd) { WaveAudio slice = new WaveAudio(wthis.getSampleRate(), wthis.getNumChannels()); if (nEnd <= nStart || nEnd > wthis.LengthInSamples || nStart < 0) { throw new Exception("Invalid slice"); } for (int ch = 0; ch < slice.data.Length; ch++) { slice.data[ch] = new double[nEnd - nStart]; Array.Copy(wthis.data[ch], nStart, slice.data[ch], 0, nEnd - nStart); } return(slice); }
/// <summary> /// Create a new sound by changing the speed/pitch of the old sound. 2.0 = an octave up, 1.0 = the same, 0.5 = down an octave /// </summary> public static WaveAudio ScalePitchAndDuration(WaveAudio w, double factor) { if (factor < 0) { throw new ArgumentException("Factor must >= 0"); } WaveAudio res = new WaveAudio(w.getSampleRate(), w.getNumChannels()); // do operation for all channels for (int i = 0; i < w.getNumChannels(); i++) { res.data[i] = scalePitchAndDurationChannel(w.data[i], factor); } return(res); }
private void button1_Click(object sender, EventArgs e) { WaveAudio test = new WaveAudio(44100, 1); test.LengthInSamples = 44100 * 7; double freq = 100;//300; PeriodicAlternative osc = new PAChangeSquare(4.0);//new PASin(); for (int i = 0; i < test.LengthInSamples; i++) { test.data[0][i] = 0.9 * osc.GetValue(i * freq * 2.0 * Math.PI / (double)44100.0); } //player.Play(test, true); WaveAudio win = new WaveAudio(strMedia + "acoust.wav"); WaveAudio wmixed = WaveAudio.Mix(WaveAudio.Modulate(test, win), 0.7, win, 0.3); player.Play(wmixed, true); }
public static double[] getAmplitudesOverTimeSegment(WaveAudio w, int nPieceSize) { int nPieces = w.data[0].Length / nPieceSize; double[] res = new double[nPieces]; for (int n = 0; n < nPieces; n++) { double total = 0; for (int i = n * nPieceSize; i < n * nPieceSize + nPieceSize; i++) { total += w.data[0][i] * w.data[0][i]; } total /= nPieceSize; res[n] = total; } return res; }
/// <summary> /// Find spectrum content of signal. Returns array, where each element represents energy at frequencies. /// For example, SpectrumContent(w, 8) returns 8 numbers. The first in the array is the amount of energy at low frequencies, and the last is the energy at highest frequencies. /// Note that FFT uses a power of 2 samples, and so all of the signal may not be used. /// </summary> /// <param name="w">Sound</param> /// <param name="nBins">Number of bins to return.</param> public static double[] SpectrumContent(WaveAudio w, int nBins) { if (w.getNumChannels() != 1) throw new Exception("Only mono supported."); double[] buffer; // FFT uses a power of 2 samples, so we might have to truncate. if (!isPowerOfTwo((uint) w.LengthInSamples)) { int nSize = (int)findNearestPowerOfTwo((uint) w.LengthInSamples); buffer = new double[nSize]; Array.Copy(w.data[0], buffer, nSize); } else buffer = w.data[0]; return getSpectrumContent(buffer, nBins); }
public static WaveAudio Wahwah(WaveAudio wOriginal, double freq, double depth, double freqofs, double res) { double startphaseleft = 0; double startphaseright = startphaseleft + Math.PI; //note that left and right channels should start pi out of phase double freq_scaled = 2.0 * Math.PI * freq / (double)wOriginal.getSampleRate(); WaveAudio w = wOriginal.Clone(); if (w.getNumChannels() == 1) effect_wahwahaud_impl(w.data[0], startphaseleft, freq_scaled, depth, freqofs, res); else { effect_wahwahaud_impl(w.data[0], startphaseleft, freq_scaled, depth, freqofs, res); effect_wahwahaud_impl(w.data[1], startphaseright, freq_scaled, depth, freqofs, res); } return w; }
public static WaveAudio Vibrato(WaveAudio wave, double freq, double width) { if (width < 0) { throw new ArgumentException("Factor must >= 0"); } WaveAudio newwave = new WaveAudio(wave.getSampleRate(), wave.getNumChannels()); // do operation for all channels for (int i = 0; i < wave.getNumChannels(); i++) { newwave.data[i] = vibratoChannel(wave.data[i], wave.getSampleRate(), width, freq); } return(newwave); }
public static WaveAudio Phaser(WaveAudio wOriginal, double freq, double fb, int depth, int stages, int drywet) { double startphaseleft = 0; double startphaseright = startphaseleft + Math.PI; //note that left and right channels should start pi out of phase double freq_scaled = 2.0 * Math.PI * freq / (double)wOriginal.getSampleRate(); WaveAudio w = wOriginal.Clone(); if (w.getNumChannels() == 1) effect_phaseraud_impl(w.data[0], freq_scaled, startphaseleft, fb, depth, stages, drywet); else { effect_phaseraud_impl(w.data[0], freq_scaled, startphaseleft, fb, depth, stages, drywet); effect_phaseraud_impl(w.data[1], freq_scaled, startphaseright, fb, depth, stages, drywet); } return w; }
//could also get continuous with window. public static WaveAudio lowPassFilter(WaveAudio w, double factor) //0.5 { //http://en.wikipedia.org/wiki/Low-pass_filter WaveAudio ret = new WaveAudio(w.getSampleRate(), w.getNumChannels()); ret.LengthInSamples = w.LengthInSamples; for (int ch = 0; ch < w.getNumChannels(); ch++) { ret.data[ch][0] = w.data[ch][0]; for (int i = 1; i < ret.data[ch].Length; i++) { ret.data[ch][i] = (1 - factor) * ret.data[ch][i - 1] + (factor) * w.data[ch][i]; } } return(ret); }
/// <summary> /// Returns a new audio object, containing a slice of the sound. /// </summary> public WaveAudio GetSlice(double fSecondsStart, double fSecondsEnd) { WaveAudio slice = new WaveAudio(this.getSampleRate(), this.getNumChannels()); int nStart = (int)(fSecondsStart * this.m_currentSampleRate); int nEnd = (int)(fSecondsEnd * this.m_currentSampleRate); if (nEnd <= nStart || nEnd > this.LengthInSamples || nStart < 0) { throw new Exception("Invalid slice"); } for (int ch = 0; ch < slice.data.Length; ch++) { slice.data[ch] = new double[nEnd - nStart]; Array.Copy(this.data[ch], nStart, slice.data[ch], 0, nEnd - nStart); } return(slice); }
//get continuous value, with a window. the 'instantaneous amplitude' //note: only from 1st channel of audio. public static double[] getAmplitudesOverTimeContinuous(WaveAudio w, int nWindowSize) { double[] res = new double[w.LengthInSamples]; double current = 0; for (int i = 0; i < w.LengthInSamples; i++) { current += w.data[0][i] * w.data[0][i]; if (i > nWindowSize) { current -= w.data[0][i - nWindowSize] * w.data[0][i - nWindowSize]; } res[i] = current / nWindowSize; } return(res); }
private static void commonLoadWaveFile(out string strFilename, out string strShortname, out WaveAudio w) { w = null; strShortname = null; strFilename = getOpenFilename(); if (strFilename == null || strFilename == "") return; try { w = new WaveAudio(strFilename); } catch (Exception er) { MessageBox.Show("Error when loading wave file: " + er.Message); return; } string[] pathsplit = strFilename.Split(new char[] { '\\' }); strShortname = pathsplit[pathsplit.Length - 1]; }
public static double[] getAmplitudesOverTime(WaveAudio w, int nPieceSize) { int nPieces = w.data[0].Length / nPieceSize; double[] res = new double[nPieces]; for (int n = 0; n < nPieces; n++) { double total = 0; for (int i = n * nPieceSize; i < n * nPieceSize + nPieceSize; i++) { total += w.data[0][i] * w.data[0][i]; } total /= nPieceSize; res[n] = total; } return(res); }
// The following create new audio without modifying original public static WaveAudio Concatenate(WaveAudio w1, WaveAudio w2) { // make sure sample rates match we could be nicer and convert automatically if (w1.m_currentSampleRate != w2.m_currentSampleRate) throw new Exception("Sample rates don't match"); if (w2.getNumChannels() != w2.getNumChannels()) throw new Exception("Number of channels don't match"); WaveAudio newwave = new WaveAudio(w1.getSampleRate(), w1.getNumChannels()); newwave.LengthInSamples = w1.LengthInSamples + w2.LengthInSamples; for (int ch = 0; ch < w1.getNumChannels(); ch++) { // source sIndex, destination, destIndex, length Array.Copy(w1.data[ch], 0, newwave.data[ch], 0, w1.data[ch].Length); Array.Copy(w2.data[ch], 0, newwave.data[ch], w1.data[ch].Length, w2.data[0].Length); } return newwave; }
// Beat detection, algorithm put together by Ben Fisher after reading some things // numbers here are arbitrary, based on what seemed to work ok. I'm sure it could be better. public static double GuessBpm(WaveAudio input) { const double minBpm = 60, maxBpm = 150; WaveAudio w = Effects.Derivative(input); // take the derivative of samples. // divide samples into chunks of size 1024. int nBufsize = 1024; double chunkframerate = input.getSampleRate() / nBufsize; // the chunks go by at this rate. // do first FFT double[][] frequencyData = SpectrumContentOverTime(w, 4, nBufsize); // create a new signal in time, consisting of the energy at lowest 1/4 freqs of the chunks. int slength = (int)Fourier.findNearestPowerOfTwo((uint)frequencyData.Length); double[] lowerdata = new double[slength]; for (int i = 0; i < slength; i++) { lowerdata[i] = frequencyData[i][0]; // the bottom 1/4 freqs (index 0-255,0Hz to 5512.5Hz or something ?) } // now take a second FFT on this new signal. Frequency should be range 0.6 to 2.5 Hz (40 to 150 Bpm). double[] reout, imgout; RawSamplesToFrequency(lowerdata, out reout, out imgout); // only keep track of output inside the range we are interested in int minFreqindex = (int)(reout.Length * ((minBpm / 60) / chunkframerate)); int maxFreqindex = (int)(reout.Length * ((maxBpm / 60) / chunkframerate)); // find the best candidate double highestEnergy = -1; int highestEnergyIndex = -1; for (int b = minFreqindex; b < maxFreqindex; b++) { double magnitude = Math.Sqrt(reout[b] * reout[b] + imgout[b] + imgout[b]); if (magnitude > highestEnergy) { highestEnergyIndex = b; highestEnergy = magnitude; } } double freqHertz = chunkframerate * (highestEnergyIndex / (double)reout.Length); double freqInBpm = freqHertz * 60; return(freqInBpm); }
public void Play(WaveAudio a, bool bAsync) { m = new MemoryStream(); bw = new BinaryWriter(m); a.SaveWaveFile(bw); pl = new SoundPlayer(m); pl.Stream.Position = 0; // This line is necessary if (bAsync) { pl.Play(); } else { pl.PlaySync(); } }
public static WaveAudio Mix(WaveAudio[] waves) { // all must have same length, sample rate, and no. of channels int nSamples = waves[0].LengthInSamples; foreach (WaveAudio w in waves) if (w.LengthInSamples != nSamples) throw new Exception("When mixing array of sounds, they all must be the same length."); int nSampleRate = waves[0].getSampleRate(); foreach (WaveAudio w in waves) if (w.getSampleRate() != nSampleRate) throw new Exception("When mixing array of sounds, they all must have same sample rate."); int nChannels = waves[0].getNumChannels(); foreach (WaveAudio w in waves) if (w.getNumChannels() != nChannels) throw new Exception("When mixing array of sounds, they all must have same amount of channels."); WaveAudio res = new WaveAudio(waves[0].getSampleRate(), waves[0].getNumChannels()); res.LengthInSamples = nSamples; for (int ch = 0; ch < nChannels; ch++) { for (int i = 0; i < nSamples; i++) { double value = 0; foreach (WaveAudio w in waves) value += w.data[ch][i]; res.data[ch][i] = value / waves.Length; } } return res; }
public static double[][] SpectrumContentOverTime(WaveAudio w, int nBins, int nSize) { if (w.getNumChannels() != 1) throw new Exception("Only mono supported."); if (!isPowerOfTwo((uint) nSize)) throw new Exception("Size must be power of 2."); int nDatapoints = w.LengthInSamples / nSize - 1; double[][] res = new double[nDatapoints][]; double[] buffer = new double[nSize]; for (int i = 0; i < nDatapoints; i++) { // get samples from this slice of time. Put it into the buffer Array.Copy(w.data[0], i * nSize, buffer, 0, nSize); res[i] = getSpectrumContent(buffer, nBins); } return res; }
public static WaveAudio Phaser(WaveAudio wOriginal, double freq, double fb, int depth, int stages, int drywet) { double startphaseleft = 0; double startphaseright = startphaseleft + Math.PI; //note that left and right channels should start pi out of phase double freq_scaled = 2.0 * Math.PI * freq / (double)wOriginal.getSampleRate(); WaveAudio w = wOriginal.Clone(); if (w.getNumChannels() == 1) { effect_phaseraud_impl(w.data[0], freq_scaled, startphaseleft, fb, depth, stages, drywet); } else { effect_phaseraud_impl(w.data[0], freq_scaled, startphaseleft, fb, depth, stages, drywet); effect_phaseraud_impl(w.data[1], freq_scaled, startphaseright, fb, depth, stages, drywet); } return(w); }
public static WaveAudio Wahwah(WaveAudio wOriginal, double freq, double depth, double freqofs, double res) { double startphaseleft = 0; double startphaseright = startphaseleft + Math.PI; //note that left and right channels should start pi out of phase double freq_scaled = 2.0 * Math.PI * freq / (double)wOriginal.getSampleRate(); WaveAudio w = wOriginal.Clone(); if (w.getNumChannels() == 1) { effect_wahwahaud_impl(w.data[0], startphaseleft, freq_scaled, depth, freqofs, res); } else { effect_wahwahaud_impl(w.data[0], startphaseleft, freq_scaled, depth, freqofs, res); effect_wahwahaud_impl(w.data[1], startphaseright, freq_scaled, depth, freqofs, res); } return(w); }
public WaveAudio doModify(WaveAudio src, int bufsize) { WaveAudio wout = new WaveAudio(src.getSampleRate(), 1); wout.LengthInSamples = src.LengthInSamples; //reuse the buffers. double[] ffreqmaghalfout = new double[bufsize / 2], ffreqanghalfout = new double[bufsize / 2]; double[] ffreqmaghalfin = new double[bufsize / 2], ffreqanghalfin = new double[bufsize / 2]; double[] fbuffertime = new double[bufsize]; for (int partnum = 0; partnum < src.LengthInSamples / bufsize; partnum++) { //copy into buffer. Array.Copy(src.data[0], partnum * bufsize, fbuffertime, 0, bufsize); double[] ffreqreal, ffreqimag; Fourier.RawSamplesToFrequency(fbuffertime, out ffreqreal, out ffreqimag); //we only care about the first half of these results. for (int i = 0; i < bufsize / 2; i++) { ffreqmaghalfin[i] = Math.Sqrt(ffreqreal[i] * ffreqreal[i] + ffreqimag[i] * ffreqimag[i]); ffreqanghalfin[i] = Math.Atan2(ffreqimag[i], ffreqreal[i]); } this.modifyAngular(ffreqmaghalfin, ffreqanghalfin, ffreqmaghalfout, ffreqanghalfout); if (partnum == 0) { this.drawPlots(ffreqmaghalfin, ffreqanghalfin, ffreqmaghalfout, ffreqanghalfout); } for (int i = 0; i < ffreqreal.Length / 2; i++) { ffreqreal[i] = ffreqmaghalfout[i] * Math.Sin(ffreqanghalfout[i]); ffreqimag[i] = ffreqmaghalfout[i] * Math.Cos(ffreqanghalfout[i]); } for (int i = ffreqreal.Length / 2; i < ffreqreal.Length; i++) { ffreqreal[i] = ffreqimag[i] = 0; } double[] fbufout; Fourier.RawFrequencyToSamples(out fbufout, ffreqreal, ffreqimag); Array.Copy(fbufout, 0, wout.data[0], partnum * bufsize, bufsize); } return(wout); }
public WaveAudio doModify(WaveAudio src, int bufsize) { WaveAudio wout = new WaveAudio(src.getSampleRate(), 1); wout.LengthInSamples = src.LengthInSamples; //reuse the buffers. double[] ffreqmaghalfout = new double[bufsize / 2], ffreqanghalfout = new double[bufsize / 2]; double[] ffreqmaghalfin = new double[bufsize / 2], ffreqanghalfin = new double[bufsize / 2]; double[] fbuffertime = new double[bufsize]; for (int index = 0; index < src.LengthInSamples - bufsize; index += bufsize / overlap) { //copy into buffer. Array.Copy(src.data[0], index, fbuffertime, 0, bufsize); double[] ffreqreal, ffreqimag; Fourier.RawSamplesToFrequency(fbuffertime, out ffreqreal, out ffreqimag); //we only care about the first half of these results. for (int i = 0; i < bufsize / 2; i++) { ffreqmaghalfin[i] = Math.Sqrt(ffreqreal[i] * ffreqreal[i] + ffreqimag[i] * ffreqimag[i]); ffreqanghalfin[i] = Math.Atan2(ffreqimag[i], ffreqreal[i]); } this.modifyAngular(ffreqmaghalfin, ffreqanghalfin, ffreqmaghalfout, ffreqanghalfout); for (int i = 0; i < ffreqreal.Length / 2; i++) { ffreqreal[i] = ffreqmaghalfout[i] * Math.Sin(ffreqanghalfout[i]); ffreqimag[i] = ffreqmaghalfout[i] * Math.Cos(ffreqanghalfout[i]); } for (int i = ffreqreal.Length / 2; i < ffreqreal.Length; i++) { ffreqreal[i] = ffreqimag[i] = 0; } double[] fbufout; Fourier.RawFrequencyToSamples(out fbufout, ffreqreal, ffreqimag); WaveAudio ww = new WaveAudio(44100, 1); ww.data[0] = fbufout; //Array.Copy(fbufout, 0, wout.data[0], partnum*bufsize, bufsize); ConstructionUtil.placeAudioRamp(wout, ww, index, (bufsize / overlapRamp)); } return(wout); }
public static WaveAudio Derivative(WaveAudio wOriginal) { WaveAudio w = wOriginal.Clone(); for (int ch = 0; ch < w.getNumChannels(); ch++) { for (int i = 0; i < w.data[ch].Length; i++) { if (i + 1 < w.data[ch].Length) { w.data[ch][i] = w.data[ch][i] - w.data[ch][i + 1]; } else { w.data[ch][i] = w.data[ch][i] - 0; } } } return(w); }
public Form1() { InitializeComponent(); this.m_audioPlayer = new AudioPlayer(); this.savedNum = SetKeyState.GetNumState(); this.savedScroll = SetKeyState.GetScrollState(); this.savedCaps = SetKeyState.GetCapsState(); if (File.Exists(@"..\..\cis.wav")) this.m_currentSound = new WaveAudio(@"..\..\cis.wav"); else if (File.Exists(@"cis.wav")) this.m_currentSound = new WaveAudio(@"cis.wav"); if (m_currentSound != null) { this.m_currentSound.setNumChannels(1, true); this.lblFilename.Text = "Loaded: cis.wav"; } }
public static void propertytests() { // these aren't the best tests. WaveAudio w1 = new WaveAudio(44100, 2); asserteq(w1.data.Length, 2, "channels"); asserteq(w1.getNumChannels(), 2, "channels"); assert(w1.data[0] != null && w1.data[1] != null, "channels"); assert(w1.data[0].Length == 1 && w1.data[1].Length == 1, "004"); asserteq(w1.getSampleRate(), 44100, "005"); WaveAudio w1m = new WaveAudio(22050, 1); asserteq(w1m.data.Length, 1, "channels"); assert(w1m.data[0] != null, "channels"); asserteq(w1m.data[0].Length, 1, "004"); asserteq(w1m.getSampleRate(), 22050, "005"); // now set some properties w1m.LengthInSamples = 100; asserteq(w1m.data[0].Length, 100); asserteqf(w1m.LengthInSeconds, 100 / (double)w1m.getSampleRate(), 0.001); }
public static void placeAudioRamp(WaveAudio target, WaveAudio source, int index, int rampWidth) { for (int ch = 0; ch < target.data.Length; ch++) { for (int j = 0; j < source.data[ch].Length; j++) { if (j < rampWidth) { target.data[ch][j + index] += source.data[ch][j] * (((double)j) / rampWidth); } else if ((source.data[ch].Length - j) < rampWidth) { target.data[ch][j + index] += source.data[ch][j] * (((double)source.data[ch].Length - j) / rampWidth); } else { target.data[ch][j + index] += source.data[ch][j]; } } } }
/// <summary> /// Find spectrum content of signal. Returns array, where each element represents energy at frequencies. /// For example, SpectrumContent(w, 8) returns 8 numbers. The first in the array is the amount of energy at low frequencies, and the last is the energy at highest frequencies. /// Note that FFT uses a power of 2 samples, and so all of the signal may not be used. /// </summary> /// <param name="w">Sound</param> /// <param name="nBins">Number of bins to return.</param> public static double[] SpectrumContent(WaveAudio w, int nBins) { if (w.getNumChannels() != 1) { throw new Exception("Only mono supported."); } double[] buffer; // FFT uses a power of 2 samples, so we might have to truncate. if (!isPowerOfTwo((uint)w.LengthInSamples)) { int nSize = (int)findNearestPowerOfTwo((uint)w.LengthInSamples); buffer = new double[nSize]; Array.Copy(w.data[0], buffer, nSize); } else { buffer = w.data[0]; } return(getSpectrumContent(buffer, nBins)); }
public static WaveAudio Mix(WaveAudio[] waves) { // all must have same length, sample rate, and no. of channels int nSamples = waves[0].LengthInSamples; foreach (WaveAudio w in waves) { if (w.LengthInSamples != nSamples) { throw new Exception("When mixing array of sounds, they all must be the same length."); } } int nSampleRate = waves[0].getSampleRate(); foreach (WaveAudio w in waves) { if (w.getSampleRate() != nSampleRate) { throw new Exception("When mixing array of sounds, they all must have same sample rate."); } } int nChannels = waves[0].getNumChannels(); foreach (WaveAudio w in waves) { if (w.getNumChannels() != nChannels) { throw new Exception("When mixing array of sounds, they all must have same amount of channels."); } } WaveAudio res = new WaveAudio(waves[0].getSampleRate(), waves[0].getNumChannels()); res.LengthInSamples = nSamples; for (int ch = 0; ch < nChannels; ch++) { for (int i = 0; i < nSamples; i++) { double value = 0; foreach (WaveAudio w in waves) { value += w.data[ch][i]; } res.data[ch][i] = value / waves.Length; } } return(res); }
private WaveAudio Go(WaveAudio win) { WaveAudio wout = new WaveAudio(44100, 1); wout.LengthInSamples = win.LengthInSamples; List<ControlFeed> activeFeeds = new List<ControlFeed>(); foreach (ControlFeed feed in this.controlArray) if (!feed.IsDisabled()) activeFeeds.Add(feed); ControlFeed[] feeds = activeFeeds.ToArray(); //get delays... actually not too efficient in terms of mem. use to precalc this... int[][] delays = new int[feeds.Length][]; for (int i = 0; i < feeds.Length; i++) { delays[i] = feeds[i].Go(wout.LengthInSamples); } // now do this for (int i = 0; i < wout.LengthInSamples; i++) { double val=0; for (int j = 0; j < feeds.Length; j++) { int index = i - delays[j][i]; double scaleFactor = feeds[j].GetMultiply(); val += getSample(win, index) * scaleFactor; // !!! !! !!!! // weird stuff here!!! //if (j==0) val += getSample(win, index) * scaleFactor; //else val += (getSample(win, index) * scaleFactor) + 0.7*getSample(wout, index) * scaleFactor; } wout.data[0][i] = val; } return wout; }
// The following create new audio without modifying original public static WaveAudio Concatenate(WaveAudio w1, WaveAudio w2) { // make sure sample rates match we could be nicer and convert automatically if (w1.m_currentSampleRate != w2.m_currentSampleRate) { throw new Exception("Sample rates don't match"); } if (w2.getNumChannels() != w2.getNumChannels()) { throw new Exception("Number of channels don't match"); } WaveAudio newwave = new WaveAudio(w1.getSampleRate(), w1.getNumChannels()); newwave.LengthInSamples = w1.LengthInSamples + w2.LengthInSamples; for (int ch = 0; ch < w1.getNumChannels(); ch++) { // source sIndex, destination, destIndex, length Array.Copy(w1.data[ch], 0, newwave.data[ch], 0, w1.data[ch].Length); Array.Copy(w2.data[ch], 0, newwave.data[ch], w1.data[ch].Length, w2.data[0].Length); } return(newwave); }
public static WaveAudio Wahwah(WaveAudio wOriginal) { return(Wahwah(wOriginal, 1.5, 0.7, 0.1, 2.5)); }
// To reuse code, both "Mix" and "Modulate" use a helper fn, ElementWiseCombination // This makes the code less straight-forward, but shorter. // Alternative would be to find a more elegant way to write ElementWiseCombination. public static WaveAudio Mix(WaveAudio w1, WaveAudio w2) { return(Mix(w1, 0.5, w2, 0.5)); }
// Helper function. It's long and gross because either sound could be longer. // I could be more clever and use Math.Max / Min to have WaveAudio longer, WaveAudio shorter // , but at least now it is readable /// <summary> /// Element-wise combination of two audio clips. For example, adding, or modulation. /// </summary> internal static WaveAudio elementWiseCombination(WaveAudio w1, WaveAudio w2, ElementWiseCombinationFn fn) { if (w1.m_currentSampleRate != w2.m_currentSampleRate) { throw new Exception("Sample rates don't match"); } if (w1.getNumChannels() != w2.getNumChannels()) { throw new Exception("Number of channels don't match"); } WaveAudio newwave = new WaveAudio(w1.getSampleRate(), w1.getNumChannels()); newwave.LengthInSamples = Math.Max(w1.LengthInSamples, w2.LengthInSamples); double val; for (int ch = 0; ch < w1.getNumChannels(); ch++) { if (w1.LengthInSamples > w2.LengthInSamples) { for (int i = 0; i < w1.LengthInSamples; i++) { if (i >= w2.LengthInSamples) { val = fn(w1.data[ch][i], 0); } else { val = fn(w1.data[ch][i], w2.data[ch][i]); } if (val > 1.0) { val = 1.0; } else if (val < -1.0) { val = -1.0; } newwave.data[ch][i] = val; } } else { for (int i = 0; i < w2.LengthInSamples; i++) { if (i >= w1.LengthInSamples) { val = fn(0, w2.data[ch][i]); } else { val = fn(w1.data[ch][i], w2.data[ch][i]); } if (val > 1.0) { val = 1.0; } else if (val < -1.0) { val = -1.0; } newwave.data[ch][i] = val; } } } return(newwave); }
public static WaveAudio Phaser(WaveAudio wOriginal, double freq) { return(Phaser(wOriginal, freq, -60, 130, 4, 255)); }
public static WaveAudio Vibrato(WaveAudio wave) { return(Vibrato(wave, 0.1, 2.0)); }
public static WaveAudio Phaser(WaveAudio wOriginal) { return(Phaser(wOriginal, .7, -60, 130, 4, 255)); }
public static WaveAudio Wahwah(WaveAudio wOriginal, double freq) { return(Wahwah(wOriginal, freq, 0.7, 0.1, 2.5)); }