开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜