【发布时间】:2026-01-11 21:50:02
【问题描述】:
下面描述的算法的结果是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;
}
}
}
}
【问题讨论】:
-
添加源代码
-
@user2136963 您使用自己编写的 descrescendo 模拟平滑过渡,而不是依赖单个“midi note”。
-
所以,你基本上是说,我应该越来越安静地演奏第一个音符,而越来越大声地演奏下一个音符?
-
这些 MIDI 合成器支持某些乐器的连奏(例如,Roland SC-88Pro 及其后续产品)。但是,如果您没有,则必须尝试使用弯音或滑音控制器来模拟它。