コード例 #1
0
        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.");
        }
コード例 #2
0
        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
        }