How to change the pitch and volume of MIDI note in Delphi?
I use the following code in my project to play midi note on key press (this is midi-related part of source):
uses
MMSystem;
var
hMidi, midimsg, notenum, instrumNum :integer;
procedure TForm1.FormCreate(Sender: TObject);
begin
midiOutOpen(@hmidi, 0, 0, 0, 0);
midimsg := $C0+$100*29; // set midi instrument to overdriven guitar (29th in GM midi instrument list)
midiOutShortMsg (hmidi, midimsg);
end;
procedure playNote(var note:integer);
begin
midimsg := $90 + (note * $100) + (127 * $10000) + 0;
midiOutShortMsg (hmidi, midimsg);
end;
procedure stopNote(var note:integer);
begin
midimsg := $80 + (note * $100) + 0 ;
midiOutShortMsg (hmidi, midimsg);
end;
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
playNote(60);
end;
procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
stopNote(60);
end;
procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
midiOutClose(hmidi);
end;
I know that there are midi messages to change the pitch and volume. But I could not find any examples of their usage in delphi. Please, help me to modify the playNote procedu开发者_Python百科re to make sound similar to guitar bend effect (smooth pitch shift of played note on semitone or whole tone up) and similarly to change the volume of note (fade-in and fade-out effect).
Thank you in advance!
I found a solution.
const
MIDI_NOTE_ON = $90;
MIDI_NOTE_OFF = $80;
MIDI_CHANGE_INSTRUMENT = $C0;
MIDI_PITCH_BEND = $E0;
function MIDIEncodeMessage(Msg, Param1, Param2: byte): integer;
begin
result := Msg + (Param1 shl 8) + (Param2 shl 16);
end;
procedure TForm4.FormClose(Sender: TObject; var Action: TCloseAction);
begin
midiOutClose(hMidi);
end;
procedure TForm4.FormCreate(Sender: TObject);
begin
playing := false;
midiOutOpen(@hMidi, 0, 0, 0, CALLBACK_NULL);
midiOutShortMsg(hMidi, MIDIEncodeMessage(MIDI_CHANGE_INSTRUMENT, 19, 0));
end;
procedure TForm4.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if playing then Exit;
ProgressBar1.Position := $2000;
midiOutShortMsg(hMidi, MIDIEncodeMessage(MIDI_PITCH_BEND,
lo(ProgressBar1.Position), hi(ProgressBar1.Position)));
midiOutShortMsg(hMidi, MIDIEncodeMessage(MIDI_NOTE_ON, 50, 127));
playing := true;
end;
procedure TForm4.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
midiOutShortMsg(hMidi, MIDIEncodeMessage(MIDI_NOTE_OFF, 50, 127));
playing := false;
end;
procedure TForm4.FormMouseWheel(Sender: TObject; Shift: TShiftState;
WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
begin
ProgressBar1.StepBy(4*WheelDelta);
midiOutShortMsg(hMidi, MIDIEncodeMessage(MIDI_PITCH_BEND,
lo(ProgressBar1.Position), hi(ProgressBar1.Position)));
end;
Drop a TProgressBar
on the form, and set its Min
and Max
to 0
and 16383
, respectively.
Then you can 'bend' the pitch by scrolling your mouse wheel. (Notice that the factor 4 I use when handling the mouse wheel might be unsuitable for your mouse and your current mouse settings.)
Sample: pitchbend.exe [I removed the EXE file from my website because Google Chrome considered it to be a malware. Although this was almost certainly a false positive, I was afraid that it would have a negative effect on my Google rankings.]
You are looking for the pitch bend message.
First four bits are 1110
and the next four indentify the channel. The next two bytes are MSB and LSB for a 14-bit pitch bend value. (First bit is always 0
.)
The "center" value of the pitch bend stick is 8192.
For example, lowest bend point on channel one:
11100000 00000000 00000000
How much the pitch goes up and down is entirely up to the synthesizer. Many synths support changing this range with an RPN, but not all.
精彩评论