public void TestFFTAudioMatrixMethod() { // harmor_HQ.bmp = 1645 (width) x 511 (height) 32 bit // test variables const string outputDirectoryFilePath = "test"; var audioSystem = BassProxy.Instance; // 0. Get Audio Data float[] audioSamples = BassProxy.ReadMonoFromFile(WAVE_INPUT_FILEPATH, SAMPLING_RATE); int width = 1645; //int width = (audioSamples.Length - WINDOW_SIZE)/ OVERLAP; int OVERLAP = (int)((double)(audioSamples.Length - WINDOW_SIZE) / (double)width); // 1. Explode samples to the range of 16 bit shorts (–32,768 to 32,767) // Matlab multiplies with 2^15 (32768) // e.g. if( max(abs(speech))<=1 ), speech = speech * 2^15; end; MathUtils.Multiply(ref audioSamples, AUDIO_MULTIPLIER); // zero pad if the audio file is too short to perform a fft if (audioSamples.Length < (WINDOW_SIZE + OVERLAP)) { int lenNew = WINDOW_SIZE + OVERLAP; Array.Resize <float>(ref audioSamples, lenNew); } // 2. Windowing // 3. FFT #region Windowing and FFT var stft = new STFT(FFTWindowType.HANNING, WINDOW_SIZE, OVERLAP); var stftdata = stft.Apply(audioSamples); // same as specgram(audio*32768, 2048, 44100, hanning(2048), 1024); stftdata.DrawMatrixImageLogValues(outputDirectoryFilePath + "_specgram.png", true, false, -1, -1, false); var spect2 = FFTUtils.CreateSpectrogramFFTW(audioSamples, WINDOW_SIZE, OVERLAP); var stftdata2 = new Matrix(spect2).Transpose(); // same as specgram(audio*32768, 2048, 44100, hanning(2048), 1024); stftdata2.DrawMatrixImageLogValues(outputDirectoryFilePath + "_specgram2.png", true, false, -1, -1, false); var spect3 = FFTUtils.CreateSpectrogramLomont(audioSamples, WINDOW_SIZE, OVERLAP); var stftdata3 = new Matrix(spect3).Transpose(); // same as specgram(audio*32768, 2048, 44100, hanning(2048), 1024); stftdata3.DrawMatrixImageLogValues(outputDirectoryFilePath + "_specgram3.png", true, false, -1, -1, false); #endregion // the matrix are too different so comparing them always fails! //Assert.That(stftdata2, Is.EqualTo(stftdata3).AsCollection.Within(0.001), "fail at [0]"); #region Inverse FFT // Perform inverse stft as well double[] audiodata_inverse_stft = stft.InverseStft(stftdata); // divide or normalize //MathUtils.Divide(ref audiodata_inverse_stft, AUDIO_MULTIPLIER); MathUtils.Normalize(ref audiodata_inverse_stft); Export.DrawGraph(audiodata_inverse_stft, outputDirectoryFilePath + "_audiodata_inverse_stft.png"); float[] audiodata_inverse_float = MathUtils.DoubleToFloat(audiodata_inverse_stft); BassProxy.SaveFile(audiodata_inverse_float, outputDirectoryFilePath + "_inverse_stft.wav", 1, SAMPLING_RATE, 32); #endregion Assert.Pass("This test was succesful."); }
static void SplitIntoSingleCycleWaveforms(string baseDirectory, string wavPath, int singleCycleLength, Dictionary <string, MassiveMapElement> map, string outputDirectory, float[] sineData) { // use path after the base dir as map key string mapKey = IOUtils.GetRightPartOfPath(wavPath, baseDirectory + Path.DirectorySeparatorChar); #region Output Correct Filenames // determine correct filename if (map.ContainsKey(mapKey)) { var mapElement = map[mapKey]; if (!mapElement.GroupName.Equals("") && !mapElement.CorrectFileName.Equals("")) { // create single cycle directory string singleCycleDirectory = Path.Combine(outputDirectory, "Single Cycle Waveforms", StringUtils.MakeValidFileName(mapElement.GroupName)); if (!Directory.Exists(singleCycleDirectory)) { Directory.CreateDirectory(singleCycleDirectory); } // create preset file directory string presetFileDirectory = Path.Combine(outputDirectory, "Zebra2 Osc Presets", StringUtils.MakeValidFileName(mapElement.GroupName)); if (!Directory.Exists(presetFileDirectory)) { Directory.CreateDirectory(presetFileDirectory); } // read audio data as mono int sampleRate = -1; int bitsPerSample = -1; long byteLength = -1; float[] audioData = BassProxy.ReadMonoFromFile(wavPath, out sampleRate, out bitsPerSample, out byteLength, BassProxy.MonoSummingType.Mix); // temporary storage for the 128 single cycle samples var waveforms = new List <float[]>(); int cycleCount = 1; // find each single cycle waveforms for (int i = 0; i < audioData.Length; i += singleCycleLength) { var singleCycleData = new float[singleCycleLength]; Array.Copy(audioData, i, singleCycleData, 0, singleCycleLength); // output the corrected filenames string newFileName = string.Format("{0}_{1}_{2}.wav", mapElement.GroupIndex, mapElement.CorrectFileName, cycleCount); string newFilePath = Path.Combine(singleCycleDirectory, newFileName); Console.Out.WriteLine("Creating file {0}.", newFilePath); BassProxy.SaveFile(singleCycleData, newFilePath, 1, sampleRate, bitsPerSample); // resample to 128 samples for u-he zebra conversion float[] singeCycle128 = MathUtils.Resample(singleCycleData, 128); // zebra only supports 16 slots if (cycleCount < 17) { waveforms.Add(singeCycle128); } else { Console.Out.WriteLine("Zebra only support 16 waves in it's wavetables."); break; } cycleCount++; } #region Save a non-morphed and a morphed version of the zebra preset // single cycle waveform array for non-morphed data float[][] soundData = MathUtils.CreateJaggedArray <float[][]>(16, 128); // single cycle waveform arrays for morphed daya float[][] morphData = MathUtils.CreateJaggedArray <float[][]>(16, 128); // distribute the waves found evenly within the 16 available slots var evenDistribution = MathUtils.GetEvenDistributionPreferEdges(waveforms.Count, 16); var indices = MathUtils.IndexOf(evenDistribution, 1); if (waveforms.Count() == 1) { // set sine data to last element (for morphing later) Array.Copy(sineData, 0, morphData[15], 0, 128); } if (indices.Count() == waveforms.Count()) { var enabledMorphSlots = new bool[16]; var enabledSoundSlots = new bool[16]; for (int i = 0; i < waveforms.Count; i++) { // add the waves successively to the normal sound data Array.Copy(waveforms[i], 0, soundData[i], 0, 128); enabledSoundSlots[i] = true; // spread out the waves to later be morphed int index = indices[i]; Array.Copy(waveforms[i], 0, morphData[index], 0, 128); enabledMorphSlots[index] = true; // before morphing this is used to tell what slots are loaded } // morph between the added waveforms (slots) Zebra2OSCPreset.MorphAllSegments(enabledMorphSlots, ref morphData); // before writing the file ensure all of the morhp slots are enabled for (int j = 0; j < 16; j++) { enabledMorphSlots[j] = true; } // save the non-morphed u-he zebra preset string zebraPreset = string.Format("{0}_{1}.h2p", mapElement.GroupIndex, mapElement.CorrectFileName); string zebraPresetFilePath = Path.Combine(presetFileDirectory, zebraPreset); Zebra2OSCPreset.Write(soundData, enabledSoundSlots, zebraPresetFilePath); // save the morphed u-he zebra preset string zebraMorphPreset = string.Format("{0}_{1}_Morph.h2p", mapElement.GroupIndex, mapElement.CorrectFileName); string zebraMorphPresetFilePath = Path.Combine(presetFileDirectory, zebraMorphPreset); Zebra2OSCPreset.Write(morphData, enabledMorphSlots, zebraMorphPresetFilePath); #endregion } else { // this should never happen Console.Out.WriteLine("Failed! Could not set wavetables correctly."); } } } #endregion }