Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I play a saxophone?

Tags:

c#

midi

protocols

The result of the algorithm, described below, is here


I have an array of notes: { 60, 63, 67, 70, 73, 77, 73, 70, 67, 63 } and a NOTE_LENGTH variable

I start with sending the first to a MidiOutput device with a standard MIDI tenor saxophone.

When the last note is played for 2/3 of NOTE_LENGTH milliseconds, I send the next one. When a note is played for NOTE_LENGTH, I stop it.

Notes are started with Midi NoteOn and stopped wit Midi NoteOff


It's easy to find where a note starts in the resulting audio. It is not smooth, while a real saxophone is. How do I achieve a smooth transition like in this video? I'm not a musician, so I don't know, what a technical difference is.


UPDATE

Source code, C# + NAudio.dll 1.3.8.0 (Note, that it may not work in later versions of 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;
            }
        }
    }
}
like image 706
user2136963 Avatar asked Feb 02 '26 03:02

user2136963


1 Answers

Use a midi pitch bend. See this SO answer for directions to some examples.

To the get the correct effect you'll probably need to do a quick pitch bend just before the end of the first note, with the bend ending at the second note pitch exactly as the second note is due to start.

You might also want to look in to interpolation of the bend to get the most realistic sound possible, i.e. rather than a liner pitch bend you might get better results with a slow-in-fast-out type interpolation (or vice-versa). I'm not sure if NAudio will support interpolation or if you'll have to implement this yourself.

like image 184
gingerbreadboy Avatar answered Feb 04 '26 17:02

gingerbreadboy



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!