/// <summary> /// Creates the sound wave of one beat with specified bpm /// </summary> /// <param name="bpm">Beats per minute</param> /// <returns></returns> public static short[] GenerateBeatWave(int bpm) { // 60 / bpm gives us the period of beat envelope // data loss from casting to int will be negligible int length = (int)(60f / bpm * Config.SAMPLE_RATE); // the beat is generated by mixing a sawtooth and a square wave short[] sawtooth = SampleWaveForm(Pitch.A3, length, x => x / 5, WaveForms.SawtoothWave, Config.SAMPLE_RATE); short[] square = SampleWaveForm(Pitch.A3, length, x => x / 7, WaveForms.SquareWave, Config.SAMPLE_RATE); short[] toneWave = Mixing.MixListOfWaves(new List <short[]> { sawtooth, square }); // to get the right loudness progression, we multiply the tone wave by an exponential function short[] wave = new short[length]; float frequency = 50; // determined by trial and error for (int i = 0; i < length; ++i) { double expValue = i < length?Math.Pow(0.0001, (double)i / length) : 0; wave[i] = Convert.ToInt16(expValue * toneWave[i]); } return(wave); }
/// <summary> /// Converts to a corresponding sound wave /// </summary> /// <param name="sampleRate">Sample rate</param> /// <param name="shift">Pitch shift, if any</param> /// <param name="waveForm">Wave form</param> /// <returns></returns> public short[] ConvertToWave(int sampleRate, Shift shift, WaveFormEquation waveForm) { int length = ConvertDurationToLength(sampleRate); List <short[]> waves = new List <short[]> { }; foreach (Pitch frequency in Frequencies) { waves.Add(Wave.SampleWaveForm(frequency, length, shift, waveForm, sampleRate)); } short[] mixed = Mixing.MixListOfWaves(waves); return(mixed); }
/// <summary> /// Generates a new recording from all the changes that have been made /// (e.g. added harmony, shifted scale). /// </summary> public void RegenerateRecording() { // dispose recording channel and recording output if they exist if (recordingOutput != null) { recordingOutput.Dispose(); } if (recordingChannel != null) { recordingChannel.Dispose(); } // generate waves from epochs short[] melody = ConcatWaves(melodyEpochs); short[] harmony = ConcatWaves(harmonyEpochs); harmony = harmony.MultiplyToLength(melody.Length); if (beatWave == null) { beatWave = GenerateBeat(bpm, melody.Length); } // mix melody, harmony and beat short[] combinedWave = Mixing.MixListOfWaves(new List <short[]> { melody, harmony, beatWave }); byte[] binaryWave = Wave.ConvertShortWaveToBytes(combinedWave); // write the result into a file using (FileStream fs = File.Create(Filename)) { Wave.WriteToStream(fs, binaryWave, melody.Length, Config.SAMPLE_RATE, Config.BITS_PER_SAMPLE, Config.CHANNELS); } // create new channel and output for playing the recording recordingChannel = new WaveChannel32(new WaveFileReader(Filename)); recordingChannel.Volume = 1.0f; recordingOutput = new DirectSoundOut(); recordingOutput.Init(recordingChannel); }