I am trying to create a theremin-like program, that plays continuous notes based on mouse cursor position. I am using Carl Franklin's MIDI Tools library to do this.
This is the code snippet I am using to play the notes.
byte pitch = 0;
while (exit == 开发者_运维技巧false)
{
byte newpitch = (byte)(32 + ((float)Cursor.Position.X / (float)SystemParameters.PrimaryScreenWidth) * 64);
if (newpitch != pitch)
{
instrument.StopNote(pitch,0);
instrument.PlayNote(newpitch, 53);
pitch = newpitch;
}
};
The problem is that the notes that are played out this way sound distinct; there is a clear transition from one note to another.
How do I play a continuous theremin like sound that shifts the pitch continuously?
This problem has little to do with MIDI, and more to do with the synthesizer generating the sound.
If you want to go from one note to the next smoothly with your current implementation, you need a synth patch that has lots of portamento. You may be able to get this to work on many patches by setting CC37 to 127 when you initialize.
Ideally, for complete smoothness, you need a synth patch that interprets the pitch bend for more than just up and down one step. Again, this has nothing to do with the values you send. Those will be 14-bit, no matter what. It is up to the synth to decide how far up/down those values go.
Depending on the synth, you can adjust its pitch bend range using the RPN for pitch bend sensitivity. You can read about it here: http://www.hoofjaw.com/forums/Topic946-32-1.aspx#bm1254
Or here: http://www.philrees.co.uk/nrpnq.htm
You should be able to do this with a MIDI pitch wheel change event.
- First byte is 0xE0 + MIDI channel number (0 means channel 1)
- Second and third bytes are the pitch wheel change value. 0x2000 means in the middle, 0x4000 is maximum (often interpreted as +2 semitones, but sequencer can do what it likes with this message).
Under the hood it is likely that Carl just uses midiOutShortMsg to send the message, which takes the three bytes converted into an DWORD. It may be that he exposes a method to let you send the DWORD directly if he doesn't have a pitch wheel change sending function.
You need to bear in mind that the top bit is not used in each of the pitch shift value bytes, so if you have your pitch value as an integer, it is turned into a short message like this:
int pitch = 0x2000; // no pitch change
byte byte2 = (byte)(pitch & 0x7f));
byte byte3 = (byte)((pitch >> 7)& 0x7f));
int shortMessage = 0xE0 + (channelNumber - 1) + (byte2 << 8) + (byte3 << 16);
It's been a long time, but I do remember that MIDI has the ability to represent pitch shifting, e.g. rolling the pitch bend wheel on a MIDI controller (synth or keyboard) is transmitted over MIDI. You could look into using this type of message to alter the pitch of a continuously playing note.
精彩评论