下面描述的算法结果是here
我有一系列笔记:{ 60, 63, 67, 70, 73, 77, 73, 70, 67, 63 }
和NOTE_LENGTH
变量
我首先将第一个发送到带有标准MIDI高音萨克斯管的MidiOutput设备。
当最后一个音符播放NOTE_LENGTH
毫秒的2/3时,我发送下一个音符。当为NOTE_LENGTH
播放一个音符时,我会将其停止。
备注以Midi NoteOn
开头,并且Midi NoteOff
停止了
很容易找到音符在结果音频中的开头位置。它是不光滑,而真正的萨克斯风是。如何在this video中实现平滑过渡?我不是音乐家,所以我不知道技术差异是什么。
更新
源代码,C#+ NAudio.dll 1.3.8.0(注意,它可能不适用于更高版本的dll)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using NAudio.Midi;
namespace Sax
{
class Program
{
static void Main(string[] args)
{
MidiOut midi_out = new MidiOut(0);
midi_out.Volume = 65535;
midi_out.Send(MidiMessage.ChangePatch(67, 0).RawData);
midi_out.Send(MidiMessage.ChangePatch(67, 1).RawData);
int iteration = 0;
int[] notes = new int[] { 60, 63, 67, 70, 73, 77, 73, 70, 67, 63 };
//int[] notes = new int[] { 60, 61, 62, 63, 64, 65, 64, 63, 62, 61 };
const int NOTE_LENGTH = 729;
while (true)
{
midi_out.Send(MidiMessage.StartNote(notes[iteration % notes.Length], 127, iteration % 2).RawData);
Thread.Sleep(1 * NOTE_LENGTH / 3);
if (iteration != 0)
midi_out.Send(MidiMessage.StopNote(notes[(iteration - 1) % notes.Length], 127, (iteration - 1) % 2).RawData);
Thread.Sleep(1 * NOTE_LENGTH / 3);
midi_out.Send(MidiMessage.StartNote(notes[(iteration + 1) % notes.Length], 127, (iteration + 1) % 2).RawData);
Thread.Sleep(NOTE_LENGTH / 3);
midi_out.Send(MidiMessage.StopNote(notes[iteration % notes.Length], 127, iteration % 2).RawData);
Thread.Sleep(NOTE_LENGTH/3);
++iteration;
}
}
}
}
答案 0 :(得分:2)
使用midi弯音。有关示例的说明,请参阅this SO answer。
为了获得正确的效果,您可能需要在第一个音符结束之前进行快速弯音,弯曲结束于第二音符音高,与第二个音符开始时完全相同。
您可能还需要查看弯曲的插值以获得最逼真的声音,即通过慢速快速输出类型插值而不是线性弯音可能会获得更好的结果(或者反之亦然)。我不确定NAudio是否支持插值,或者你是否必须自己实现。