828 lines
32 KiB
ObjectPascal
828 lines
32 KiB
ObjectPascal
|
|
{**************************************************************************************************}
|
|||
|
|
{ }
|
|||
|
|
{ Project JEDI Code Library (JCL) }
|
|||
|
|
{ }
|
|||
|
|
{ The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); }
|
|||
|
|
{ you may not use this file except in compliance with the License. You may obtain a copy of the }
|
|||
|
|
{ License at http://www.mozilla.org/MPL/ }
|
|||
|
|
{ }
|
|||
|
|
{ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF }
|
|||
|
|
{ ANY KIND, either express or implied. See the License for the specific language governing rights }
|
|||
|
|
{ and limitations under the License. }
|
|||
|
|
{ }
|
|||
|
|
{ The Original Code is JclMIDI.pas. }
|
|||
|
|
{ }
|
|||
|
|
{ The Initial Developer of the Original Code is Robert Rossmair. }
|
|||
|
|
{ Portions created by Robert Rossmair are Copyright (C) Robert Rossmair. All rights reserved. }
|
|||
|
|
{ }
|
|||
|
|
{ Contributor(s): }
|
|||
|
|
{ Robert Rossmair }
|
|||
|
|
{ }
|
|||
|
|
{**************************************************************************************************}
|
|||
|
|
{ }
|
|||
|
|
{ Platform-independent MIDI declarations }
|
|||
|
|
{ }
|
|||
|
|
{ Unit owner: Robert Rossmair }
|
|||
|
|
{ }
|
|||
|
|
{**************************************************************************************************}
|
|||
|
|
|
|||
|
|
// Last modified: $Date: 2005/08/07 13:09:54 $
|
|||
|
|
// For history see end of file
|
|||
|
|
|
|||
|
|
unit JclMIDI;
|
|||
|
|
|
|||
|
|
{$I jcl.inc}
|
|||
|
|
|
|||
|
|
interface
|
|||
|
|
|
|||
|
|
uses
|
|||
|
|
Classes,
|
|||
|
|
JclBase;
|
|||
|
|
|
|||
|
|
// manifest constants for MIDI message protocol
|
|||
|
|
const
|
|||
|
|
// MIDI Status Bytes for Channel Voice Messages
|
|||
|
|
MIDIMsgNoteOff = $80;
|
|||
|
|
MIDIMsgNoteOn = $90;
|
|||
|
|
MIDIMsgPolyKeyPressure = $A0;
|
|||
|
|
MIDIMsgControlChange = $B0;
|
|||
|
|
MIDIMsgProgramChange = $C0;
|
|||
|
|
MIDIMsgChannelKeyPressure = $D0;
|
|||
|
|
MIDIMsgAftertouch = MIDIMsgChannelKeyPressure; // Synonym
|
|||
|
|
MIDIMsgPitchWheelChange = $E0;
|
|||
|
|
// MIDI Status Bytes for System Common Messages
|
|||
|
|
MIDIMsgSysEx = $F0;
|
|||
|
|
MIDIMsgMTCQtrFrame = $F1; // MIDI Time Code Qtr. Frame
|
|||
|
|
MIDIMsgSongPositionPtr = $F2;
|
|||
|
|
MIDIMsgSongSelect = $F3;
|
|||
|
|
MIDIMsgTuneRequest = $F6;
|
|||
|
|
MIDIMsgEOX = $F7; // marks end of system exclusive message
|
|||
|
|
|
|||
|
|
// MIDI Status Bytes for System Real-Time Messages
|
|||
|
|
MIDIMsgTimingClock = $F8;
|
|||
|
|
MIDIMsgStartSequence = $FA;
|
|||
|
|
MIDIMsgContinueSequence = $FB;
|
|||
|
|
MIDIMsgStopSequence = $FC;
|
|||
|
|
MIDIMsgActiveSensing = $FE;
|
|||
|
|
MIDIMsgSystemReset = $FF;
|
|||
|
|
|
|||
|
|
// MIDICC...: MIDI Control Change Messages
|
|||
|
|
|
|||
|
|
// Continuous Controllers MSB
|
|||
|
|
MIDICCBankSelect = $00;
|
|||
|
|
MIDICCModulationWheel = $01;
|
|||
|
|
MIDICCBreathControl = $02;
|
|||
|
|
MIDICCFootController = $04;
|
|||
|
|
MIDICCPortamentoTime = $05;
|
|||
|
|
MIDICCDataEntry = $06;
|
|||
|
|
MIDICCChannelVolume = $07;
|
|||
|
|
MIDICCMainVolume = MIDICCChannelVolume;
|
|||
|
|
MIDICCBalance = $08;
|
|||
|
|
MIDICCPan = $0A;
|
|||
|
|
MIDICCExpression = $0B;
|
|||
|
|
MIDICCEffectControl = $0C;
|
|||
|
|
MIDICCEffectControl2 = $0D;
|
|||
|
|
MIDICCGeneralPurpose1 = $10;
|
|||
|
|
MIDICCGeneralPurpose2 = $11;
|
|||
|
|
MIDICCGeneralPurpose3 = $12;
|
|||
|
|
MIDICCGeneralPurpose4 = $13;
|
|||
|
|
// Continuous Controllers LSB
|
|||
|
|
MIDICCBankSelectLSB = $20;
|
|||
|
|
MIDICCModulationWheelLSB = $21;
|
|||
|
|
MIDICCBreathControlLSB = $22;
|
|||
|
|
MIDICCFootControllerLSB = $24;
|
|||
|
|
MIDICCPortamentoTimeLSB = $25;
|
|||
|
|
MIDICCDataEntryLSB = $26;
|
|||
|
|
MIDICCChannelVolumeLSB = $27;
|
|||
|
|
MIDICCMainVolumeLSB = MIDICCChannelVolumeLSB;
|
|||
|
|
MIDICCBalanceLSB = $28;
|
|||
|
|
MIDICCPanLSB = $2A;
|
|||
|
|
MIDICCExpressionLSB = $2B;
|
|||
|
|
MIDICCEffectControlLSB = $2C;
|
|||
|
|
MIDICCEffectControl2LSB = $2D;
|
|||
|
|
MIDICCGeneralPurpose1LSB = $30;
|
|||
|
|
MIDICCGeneralPurpose2LSB = $31;
|
|||
|
|
MIDICCGeneralPurpose3LSB = $32;
|
|||
|
|
MIDICCGeneralPurpose4LSB = $33;
|
|||
|
|
// Switches
|
|||
|
|
MIDICCSustain = $40;
|
|||
|
|
MIDICCPortamento = $41;
|
|||
|
|
MIDICCSustenuto = $42;
|
|||
|
|
MIDICCSoftPedal = $43;
|
|||
|
|
MIDICCLegato = $44;
|
|||
|
|
MIDICCHold2 = $45;
|
|||
|
|
|
|||
|
|
MIDICCSound1 = $46; // (Sound Variation)
|
|||
|
|
MIDICCSound2 = $47; // (Timbre/Harmonic Intens.)
|
|||
|
|
MIDICCSound3 = $48; // (Release Time)
|
|||
|
|
MIDICCSound4 = $49; // (Attack Time)
|
|||
|
|
MIDICCSound5 = $4A; // (Brightness)
|
|||
|
|
MIDICCSound6 = $4B; // (Decay Time)
|
|||
|
|
MIDICCSound7 = $4C; // (Vibrato Rate)
|
|||
|
|
MIDICCSound8 = $4D; // (Vibrato Depth)
|
|||
|
|
MIDICCSound9 = $4E; // (Vibrato Delay)
|
|||
|
|
MIDICCSound10 = $4F; //
|
|||
|
|
|
|||
|
|
MIDICCGeneralPurpose5 = $50;
|
|||
|
|
MIDICCGeneralPurpose6 = $51;
|
|||
|
|
MIDICCGeneralPurpose7 = $52;
|
|||
|
|
MIDICCGeneralPurpose8 = $53;
|
|||
|
|
MIDICCPortamentoControl = $54;
|
|||
|
|
|
|||
|
|
MIDICCReverbSendLevel = $5B;
|
|||
|
|
MIDICCEffects2Depth = $5C;
|
|||
|
|
MIDICCTremoloDepth = MIDICCEffects2Depth;
|
|||
|
|
MIDICCChorusSendLevel = $5D;
|
|||
|
|
MIDICCEffects4Depth = $5E;
|
|||
|
|
MIDICCCelesteDepth = MIDICCEffects4Depth;
|
|||
|
|
MIDICCEffects5Depth = $5F;
|
|||
|
|
MIDICCPhaserDepth = MIDICCEffects5Depth;
|
|||
|
|
|
|||
|
|
MIDICCDataEntryInc = $60;
|
|||
|
|
MIDICCDataEntryDec = $61;
|
|||
|
|
MIDICCNonRegParamNumLSB = $62;
|
|||
|
|
MIDICCNonRegParamNumMSB = $63;
|
|||
|
|
MIDICCRegParamNumLSB = $64;
|
|||
|
|
MIDICCRegParamNumMSB = $65;
|
|||
|
|
|
|||
|
|
// Registered Parameter Numbers [CC# 65H,64H]
|
|||
|
|
// -----------------------------------------------------------
|
|||
|
|
// CC#65 (MSB) | CC#64 (LSB) | Function
|
|||
|
|
// Hex|Dec| | Hex|Dec| |
|
|||
|
|
// - - - - - - | - - - - - - |- - - - - - - - - - - - - - - -
|
|||
|
|
// 00 = 0 | 00 = 0 | Pitch Bend Sensitivity
|
|||
|
|
// 00 = 0 | 01 = 1 | Channel Fine Tuning
|
|||
|
|
// 00 = 0 | 02 = 2 | Channel Coarse Tuning
|
|||
|
|
// 00 = 0 | 03 = 3 | Tuning Program Change
|
|||
|
|
// 00 = 0 | 04 = 4 | Tuning Bank Select
|
|||
|
|
|
|||
|
|
// Channel Mode Messages (Control Change >= $78)
|
|||
|
|
MIDICCAllSoundOff = $78;
|
|||
|
|
MIDICCResetAllControllers = $79;
|
|||
|
|
MIDICCLocalControl = $7A;
|
|||
|
|
MIDICCAllNotesOff = $7B;
|
|||
|
|
|
|||
|
|
MIDICCOmniModeOff = $7C;
|
|||
|
|
MIDICCOmniModeOn = $7D;
|
|||
|
|
MIDICCMonoModeOn = $7E;
|
|||
|
|
MIDICCPolyModeOn = $7F;
|
|||
|
|
|
|||
|
|
type
|
|||
|
|
TMIDIChannel = 1..16;
|
|||
|
|
TMIDIDataByte = 0..$7F; // 7 bits
|
|||
|
|
TMIDIDataWord = 0..$3FFF; // 14 bits
|
|||
|
|
TMIDIStatusByte = $80..$FF;
|
|||
|
|
TMIDIVelocity = TMIDIDataByte;
|
|||
|
|
TMIDIKey = TMIDIDataByte;
|
|||
|
|
TMIDINote = TMIDIKey;
|
|||
|
|
|
|||
|
|
const
|
|||
|
|
// Helper definitions
|
|||
|
|
MIDIDataMask = $7F;
|
|||
|
|
MIDIDataWordMask = $3FFF;
|
|||
|
|
MIDIChannelMsgMask = $F0;
|
|||
|
|
MIDIInvalidStatus = TMIDIStatusByte(0);
|
|||
|
|
BitsPerMIDIDataByte = 7;
|
|||
|
|
BitsPerMIDIDataWord = BitsPerMIDIDataByte * 2;
|
|||
|
|
MIDIPitchWheelCenter = 1 shl (BitsPerMIDIDataWord - 1);
|
|||
|
|
|
|||
|
|
type
|
|||
|
|
TMIDINotes = set of TMIDINote;
|
|||
|
|
|
|||
|
|
TSingleNoteTuningData = packed record
|
|||
|
|
case Integer of
|
|||
|
|
0:
|
|||
|
|
(Key: TMIDINote; Frequency: array [0..2] of TMIDIDataByte);
|
|||
|
|
1:
|
|||
|
|
(DWord: LongWord);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
EJclMIDIError = class(EJclError);
|
|||
|
|
|
|||
|
|
// MIDI Out
|
|||
|
|
IJclMIDIOut = interface
|
|||
|
|
['{A29C3EBD-EB70-4C72-BEC5-700AF57FD4C8}']
|
|||
|
|
// property access methods
|
|||
|
|
function GetActiveNotes(Channel: TMIDIChannel): TMIDINotes;
|
|||
|
|
function GetName: string;
|
|||
|
|
function GetMIDIStatus: TMIDIStatusByte;
|
|||
|
|
function GetRunningStatusEnabled: Boolean;
|
|||
|
|
procedure SetRunningStatusEnabled(const Value: Boolean);
|
|||
|
|
// General message send method
|
|||
|
|
procedure SendMessage(const Data: array of Byte);
|
|||
|
|
// Channel Voice Messages
|
|||
|
|
procedure SendNoteOff(Channel: TMIDIChannel; Key: TMIDINote; Velocity: TMIDIDataByte = $40);
|
|||
|
|
procedure SendNoteOn(Channel: TMIDIChannel; Key: TMIDINote; Velocity: TMIDIDataByte);
|
|||
|
|
procedure SendPolyphonicKeyPressure(Channel: TMIDIChannel; Key: TMIDINote; Value: TMIDIDataByte);
|
|||
|
|
procedure SendControlChange(Channel: TMIDIChannel; ControllerNum, Value: TMIDIDataByte);
|
|||
|
|
// High Resolution "macro" for controller numbers <= $13, sends upper 7 bits first,
|
|||
|
|
// lower 7 bits per additional <controller name>LSB message afterwards
|
|||
|
|
procedure SendControlChangeHR(Channel: TMIDIChannel; ControllerNum: TMIDIDataByte; Value: TMIDIDataWord);
|
|||
|
|
procedure SendSwitchChange(Channel: TMIDIChannel; ControllerNum: TMIDIDataByte; Value: Boolean);
|
|||
|
|
procedure SendProgramChange(Channel: TMIDIChannel; ProgramNum: TMIDIDataByte);
|
|||
|
|
procedure SendChannelPressure(Channel: TMIDIChannel; Value: TMIDIDataByte);
|
|||
|
|
procedure SendPitchWheelChange(Channel: TMIDIChannel; Value: TMIDIDataWord);
|
|||
|
|
procedure SendPitchWheelPos(Channel: TMIDIChannel; Value: Single);
|
|||
|
|
// Control Change Messages
|
|||
|
|
procedure SelectProgram(Channel: TMIDIChannel; BankNum: TMIDIDataWord; ProgramNum: TMIDIDataByte);
|
|||
|
|
procedure SendModulationWheelChange(Channel: TMIDIChannel; Value: TMidiDataByte);
|
|||
|
|
procedure SendBreathControlChange(Channel: TMIDIChannel; Value: TMidiDataByte);
|
|||
|
|
procedure SendFootControllerChange(Channel: TMIDIChannel; Value: TMidiDataByte);
|
|||
|
|
procedure SendPortamentoTimeChange(Channel: TMIDIChannel; Value: TMidiDataByte);
|
|||
|
|
procedure SendDataEntry(Channel: TMIDIChannel; Value: TMidiDataByte);
|
|||
|
|
procedure SendChannelVolumeChange(Channel: TMIDIChannel; Value: TMidiDataByte);
|
|||
|
|
procedure SendBalanceChange(Channel: TMIDIChannel; Value: TMidiDataByte);
|
|||
|
|
procedure SendPanChange(Channel: TMIDIChannel; Value: TMidiDataByte);
|
|||
|
|
procedure SendExpressionChange(Channel: TMIDIChannel; Value: TMidiDataByte);
|
|||
|
|
// "high resolution" variants
|
|||
|
|
procedure SendModulationWheelChangeHR(Channel: TMIDIChannel; Value: TMidiDataWord);
|
|||
|
|
procedure SendBreathControlChangeHR(Channel: TMIDIChannel; Value: TMidiDataWord);
|
|||
|
|
procedure SendFootControllerChangeHR(Channel: TMIDIChannel; Value: TMidiDataWord);
|
|||
|
|
procedure SendPortamentoTimeChangeHR(Channel: TMIDIChannel; Value: TMidiDataWord);
|
|||
|
|
procedure SendDataEntryHR(Channel: TMIDIChannel; Value: TMidiDataWord);
|
|||
|
|
procedure SendChannelVolumeChangeHR(Channel: TMIDIChannel; Value: TMidiDataWord);
|
|||
|
|
procedure SendBalanceChangeHR(Channel: TMIDIChannel; Value: TMidiDataWord);
|
|||
|
|
procedure SendPanChangeHR(Channel: TMIDIChannel; Value: TMidiDataWord);
|
|||
|
|
procedure SendExpressionChangeHR(Channel: TMIDIChannel; Value: TMidiDataWord);
|
|||
|
|
// Control Change Messages: Switches
|
|||
|
|
procedure SwitchSustain(Channel: TMIDIChannel; Value: Boolean);
|
|||
|
|
procedure SwitchPortamento(Channel: TMIDIChannel; Value: Boolean);
|
|||
|
|
procedure SwitchSostenuto(Channel: TMIDIChannel; Value: Boolean);
|
|||
|
|
procedure SwitchSoftPedal(Channel: TMIDIChannel; Value: Boolean);
|
|||
|
|
procedure SwitchLegato(Channel: TMIDIChannel; Value: Boolean);
|
|||
|
|
procedure SwitchHold2(Channel: TMIDIChannel; Value: Boolean);
|
|||
|
|
// Channel Mode Messages
|
|||
|
|
procedure SwitchAllSoundOff(Channel: TMIDIChannel);
|
|||
|
|
procedure ResetAllControllers(Channel: TMIDIChannel);
|
|||
|
|
procedure SwitchLocalControl(Channel: TMIDIChannel; Value: Boolean);
|
|||
|
|
procedure SwitchAllNotesOff(Channel: TMIDIChannel);
|
|||
|
|
procedure SwitchOmniModeOff(Channel: TMIDIChannel);
|
|||
|
|
procedure SwitchOmniModeOn(Channel: TMIDIChannel);
|
|||
|
|
procedure SwitchMonoModeOn(Channel: TMIDIChannel; ChannelCount: Integer);
|
|||
|
|
procedure SwitchPolyModeOn(Channel: TMIDIChannel);
|
|||
|
|
//
|
|||
|
|
procedure SendSingleNoteTuningChange(const TargetDeviceID, TuningProgramNum: TMidiDataByte;
|
|||
|
|
const TuningData: array of TSingleNoteTuningData);
|
|||
|
|
function NoteIsOn(Channel: TMIDIChannel; Key: TMIDINote): Boolean;
|
|||
|
|
procedure SwitchActiveNotesOff(Channel: TMIDIChannel); overload;
|
|||
|
|
procedure SwitchActiveNotesOff; overload;
|
|||
|
|
// Properties
|
|||
|
|
property ActiveNotes[Channel: TMIDIChannel]: TMIDINotes read GetActiveNotes;
|
|||
|
|
property Name: string read GetName;
|
|||
|
|
property LocalControl[Channel: TMIDIChannel]: Boolean write SwitchLocalControl;
|
|||
|
|
property MIDIStatus: TMIDIStatusByte read GetMIDIStatus;
|
|||
|
|
// Tribute to some braindead devices which cannot handle running status (e.g. ESS Solo 1 Win2k driver)
|
|||
|
|
property RunningStatusEnabled: Boolean read GetRunningStatusEnabled write SetRunningStatusEnabled;
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
// Abstract MIDI Out device class
|
|||
|
|
TJclMIDIOut = class(TInterfacedObject, IJclMIDIOut)
|
|||
|
|
private
|
|||
|
|
FMIDIStatus: TMIDIStatusByte;
|
|||
|
|
FRunningStatusEnabled: Boolean;
|
|||
|
|
FActiveNotes: array [TMIDIChannel] of TMIDINotes;
|
|||
|
|
protected
|
|||
|
|
function GetActiveNotes(Channel: TMIDIChannel): TMIDINotes;
|
|||
|
|
function GetName: string; virtual; abstract;
|
|||
|
|
function GetMIDIStatus: TMIDIStatusByte;
|
|||
|
|
function IsRunningStatus(StatusByte: TMIDIStatusByte): Boolean;
|
|||
|
|
function GetRunningStatusEnabled: Boolean;
|
|||
|
|
procedure SetRunningStatusEnabled(const Value: Boolean);
|
|||
|
|
procedure SendChannelMessage(Msg: TMIDIStatusByte; Channel: TMIDIChannel;
|
|||
|
|
Data1, Data2: TMIDIDataByte);
|
|||
|
|
procedure DoSendMessage(const Data: array of Byte); virtual; abstract;
|
|||
|
|
procedure SendMessage(const Data: array of Byte);
|
|||
|
|
public
|
|||
|
|
destructor Destroy; override;
|
|||
|
|
// Channel Voice Messages
|
|||
|
|
procedure SendNoteOff(Channel: TMIDIChannel; Key: TMIDINote; Velocity: TMIDIDataByte = $40);
|
|||
|
|
procedure SendNoteOn(Channel: TMIDIChannel; Key: TMIDINote; Velocity: TMIDIDataByte);
|
|||
|
|
procedure SendPolyphonicKeyPressure(Channel: TMIDIChannel; Key: TMIDINote; Value: TMIDIDataByte);
|
|||
|
|
procedure SendControlChange(Channel: TMIDIChannel; ControllerNum, Value: TMIDIDataByte);
|
|||
|
|
procedure SendControlChangeHR(Channel: TMIDIChannel; ControllerNum: TMIDIDataByte; Value: TMIDIDataWord);
|
|||
|
|
procedure SendSwitchChange(Channel: TMIDIChannel; ControllerNum: TMIDIDataByte; Value: Boolean);
|
|||
|
|
procedure SendProgramChange(Channel: TMIDIChannel; ProgramNum: TMIDIDataByte);
|
|||
|
|
procedure SendChannelPressure(Channel: TMIDIChannel; Value: TMIDIDataByte);
|
|||
|
|
procedure SendPitchWheelChange(Channel: TMIDIChannel; Value: TMIDIDataWord);
|
|||
|
|
procedure SendPitchWheelPos(Channel: TMIDIChannel; Value: Single);
|
|||
|
|
// Control Change Messages
|
|||
|
|
procedure SelectProgram(Channel: TMIDIChannel; BankNum: TMIDIDataWord; ProgramNum: TMIDIDataByte);
|
|||
|
|
procedure SendModulationWheelChange(Channel: TMIDIChannel; Value: TMidiDataByte);
|
|||
|
|
procedure SendBreathControlChange(Channel: TMIDIChannel; Value: TMidiDataByte);
|
|||
|
|
procedure SendFootControllerChange(Channel: TMIDIChannel; Value: TMidiDataByte);
|
|||
|
|
procedure SendPortamentoTimeChange(Channel: TMIDIChannel; Value: TMidiDataByte);
|
|||
|
|
procedure SendDataEntry(Channel: TMIDIChannel; Value: TMidiDataByte);
|
|||
|
|
procedure SendChannelVolumeChange(Channel: TMIDIChannel; Value: TMidiDataByte);
|
|||
|
|
procedure SendBalanceChange(Channel: TMIDIChannel; Value: TMidiDataByte);
|
|||
|
|
procedure SendPanChange(Channel: TMIDIChannel; Value: TMidiDataByte);
|
|||
|
|
procedure SendExpressionChange(Channel: TMIDIChannel; Value: TMidiDataByte);
|
|||
|
|
// ...high Resolution
|
|||
|
|
procedure SendModulationWheelChangeHR(Channel: TMIDIChannel; Value: TMidiDataWord);
|
|||
|
|
procedure SendBreathControlChangeHR(Channel: TMIDIChannel; Value: TMidiDataWord);
|
|||
|
|
procedure SendFootControllerChangeHR(Channel: TMIDIChannel; Value: TMidiDataWord);
|
|||
|
|
procedure SendPortamentoTimeChangeHR(Channel: TMIDIChannel; Value: TMidiDataWord);
|
|||
|
|
procedure SendDataEntryHR(Channel: TMIDIChannel; Value: TMidiDataWord);
|
|||
|
|
procedure SendChannelVolumeChangeHR(Channel: TMIDIChannel; Value: TMidiDataWord);
|
|||
|
|
procedure SendBalanceChangeHR(Channel: TMIDIChannel; Value: TMidiDataWord);
|
|||
|
|
procedure SendPanChangeHR(Channel: TMIDIChannel; Value: TMidiDataWord);
|
|||
|
|
procedure SendExpressionChangeHR(Channel: TMIDIChannel; Value: TMidiDataWord);
|
|||
|
|
// Control Change Messages: Switches
|
|||
|
|
procedure SwitchSustain(Channel: TMIDIChannel; Value: Boolean);
|
|||
|
|
procedure SwitchPortamento(Channel: TMIDIChannel; Value: Boolean);
|
|||
|
|
procedure SwitchSostenuto(Channel: TMIDIChannel; Value: Boolean);
|
|||
|
|
procedure SwitchSoftPedal(Channel: TMIDIChannel; Value: Boolean);
|
|||
|
|
procedure SwitchLegato(Channel: TMIDIChannel; Value: Boolean);
|
|||
|
|
procedure SwitchHold2(Channel: TMIDIChannel; Value: Boolean);
|
|||
|
|
// Channel Mode Messages
|
|||
|
|
procedure SwitchAllSoundOff(Channel: TMIDIChannel);
|
|||
|
|
procedure ResetAllControllers(Channel: TMIDIChannel);
|
|||
|
|
procedure SwitchLocalControl(Channel: TMIDIChannel; Value: Boolean);
|
|||
|
|
procedure SwitchAllNotesOff(Channel: TMIDIChannel);
|
|||
|
|
procedure SwitchOmniModeOff(Channel: TMIDIChannel);
|
|||
|
|
procedure SwitchOmniModeOn(Channel: TMIDIChannel);
|
|||
|
|
procedure SwitchMonoModeOn(Channel: TMIDIChannel; ChannelCount: Integer);
|
|||
|
|
procedure SwitchPolyModeOn(Channel: TMIDIChannel);
|
|||
|
|
//
|
|||
|
|
procedure SendSingleNoteTuningChange(const TargetDeviceID, TuningProgramNum: TMidiDataByte;
|
|||
|
|
const TuningData: array of TSingleNoteTuningData);
|
|||
|
|
function NoteIsOn(Channel: TMIDIChannel; Key: TMIDINote): Boolean;
|
|||
|
|
procedure SwitchActiveNotesOff(Channel: TMIDIChannel); overload;
|
|||
|
|
procedure SwitchActiveNotesOff; overload;
|
|||
|
|
property ActiveNotes[Channel: TMIDIChannel]: TMIDINotes read GetActiveNotes;
|
|||
|
|
property Name: string read GetName;
|
|||
|
|
property RunningStatusEnabled: Boolean read GetRunningStatusEnabled write SetRunningStatusEnabled;
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
function MIDIOut(DeviceID: Cardinal = 0): IJclMIDIOut;
|
|||
|
|
procedure GetMidiOutputs(const List: TStrings);
|
|||
|
|
function MIDISingleNoteTuningData(Key: TMIDINote; Frequency: Single): TSingleNoteTuningData;
|
|||
|
|
function MIDINoteToStr(Note: TMIDINote): string;
|
|||
|
|
|
|||
|
|
implementation
|
|||
|
|
|
|||
|
|
uses
|
|||
|
|
SysUtils,
|
|||
|
|
{$IFDEF MSWINDOWS}
|
|||
|
|
JclWinMIDI,
|
|||
|
|
{$ENDIF MSWINDOWS}
|
|||
|
|
{$IFDEF UNIX}
|
|||
|
|
//JclUnixMIDI,
|
|||
|
|
{$ENDIF UNIX}
|
|||
|
|
JclResources;
|
|||
|
|
|
|||
|
|
{$IFDEF UNIX}
|
|||
|
|
procedure ErrorNotImplemented;
|
|||
|
|
begin
|
|||
|
|
raise EJclInternalError.CreateRes(@RsMidiNotImplemented);
|
|||
|
|
end;
|
|||
|
|
{$ENDIF UNIX}
|
|||
|
|
|
|||
|
|
function MIDIOut(DeviceID: Cardinal = 0): IJclMIDIOut;
|
|||
|
|
begin
|
|||
|
|
Result := nil;
|
|||
|
|
{$IFDEF MSWINDOWS}
|
|||
|
|
Result := JclWinMIDI.MIDIOut(DeviceID);
|
|||
|
|
{$ENDIF MSWINDOWS}
|
|||
|
|
{$IFDEF UNIX}
|
|||
|
|
{ TODO -oRobert Rossmair : Unix MIDI Out }
|
|||
|
|
//Result := JclUnixMIDI.MidiOut(DeviceID);
|
|||
|
|
ErrorNotImplemented;
|
|||
|
|
{$ENDIF UNIX}
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure GetMidiOutputs(const List: TStrings);
|
|||
|
|
begin
|
|||
|
|
{$IFDEF MSWINDOWS}
|
|||
|
|
JclWinMIDI.GetMidiOutputs(List);
|
|||
|
|
{$ENDIF MSWINDOWS}
|
|||
|
|
{$IFDEF UNIX}
|
|||
|
|
{ TODO -oRobert Rossmair : Unix GetMIDIOutputs }
|
|||
|
|
//JclUnixMIDI.GetMidiOutputs(List);
|
|||
|
|
ErrorNotImplemented;
|
|||
|
|
{$ENDIF UNIX}
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
function MIDISingleNoteTuningData(Key: TMIDINote; Frequency: Single): TSingleNoteTuningData;
|
|||
|
|
var
|
|||
|
|
F: Cardinal;
|
|||
|
|
begin
|
|||
|
|
Result.Key := Key;
|
|||
|
|
F := Trunc(Frequency * (1 shl BitsPerMIDIDataWord));
|
|||
|
|
Result.Frequency[0] := (F shr BitsPerMIDIDataWord) and MIDIDataMask;
|
|||
|
|
Result.Frequency[1] := (F shr BitsPerMIDIDataByte) and MIDIDataMask;
|
|||
|
|
Result.Frequency[2] := F and MIDIDataMask;
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure CheckMIDIChannelNum(Channel: TMIDIChannel);
|
|||
|
|
begin
|
|||
|
|
if (Channel < Low(TMIDIChannel)) or (Channel > High(TMIDIChannel)) then
|
|||
|
|
raise EJclMIDIError.CreateResFmt(@RsMidiInvalidChannelNum, [Channel]);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
function MIDINoteToStr(Note: TMIDINote): string;
|
|||
|
|
const
|
|||
|
|
HalftonesPerOctave = 12;
|
|||
|
|
begin
|
|||
|
|
case Note mod HalftonesPerOctave of
|
|||
|
|
0:
|
|||
|
|
Result := RsOctaveC;
|
|||
|
|
1:
|
|||
|
|
Result := RsOctaveCSharp;
|
|||
|
|
2:
|
|||
|
|
Result := RsOctaveD;
|
|||
|
|
3:
|
|||
|
|
Result := RsOctaveDSharp;
|
|||
|
|
4:
|
|||
|
|
Result := RsOctaveE;
|
|||
|
|
5:
|
|||
|
|
Result := RsOctaveF;
|
|||
|
|
6:
|
|||
|
|
Result := RsOctaveFSharp;
|
|||
|
|
7:
|
|||
|
|
Result := RsOctaveG;
|
|||
|
|
8:
|
|||
|
|
Result := RsOctaveGSharp;
|
|||
|
|
9:
|
|||
|
|
Result := RsOctaveA;
|
|||
|
|
10:
|
|||
|
|
Result := RsOctaveASharp;
|
|||
|
|
11:
|
|||
|
|
Result := RsOctaveB;
|
|||
|
|
end;
|
|||
|
|
Result := Format('%s%d', [Result, Note div HalftonesPerOctave - 2]);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
// TJclMIDIOut
|
|||
|
|
destructor TJclMIDIOut.Destroy;
|
|||
|
|
begin
|
|||
|
|
SwitchActiveNotesOff;
|
|||
|
|
inherited Destroy;
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
function TJclMIDIOut.GetActiveNotes(Channel: TMIDIChannel): TMIDINotes;
|
|||
|
|
begin
|
|||
|
|
CheckMIDIChannelNum(Channel);
|
|||
|
|
Result := FActiveNotes[Channel];
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendChannelMessage(Msg: TMIDIStatusByte;
|
|||
|
|
Channel: TMIDIChannel; Data1, Data2: TMIDIDataByte);
|
|||
|
|
begin
|
|||
|
|
SendMessage([Msg or (Channel - Low(Channel)), Data1, Data2]);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
function TJclMIDIOut.GetRunningStatusEnabled: Boolean;
|
|||
|
|
begin
|
|||
|
|
Result := FRunningStatusEnabled;
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
function TJclMIDIOut.NoteIsOn(Channel: TMIDIChannel; Key: TMIDINote): Boolean;
|
|||
|
|
begin
|
|||
|
|
Result := Key in FActiveNotes[Channel];
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendNoteOff(Channel: TMIDIChannel; Key: TMIDINote; Velocity: TMIDIDataByte);
|
|||
|
|
begin
|
|||
|
|
SendChannelMessage(MIDIMsgNoteOff, Channel, Key, Velocity);
|
|||
|
|
Exclude(FActiveNotes[Channel], Key);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendNoteOn(Channel: TMIDIChannel; Key: TMIDINote; Velocity: TMIDIDataByte);
|
|||
|
|
begin
|
|||
|
|
SendChannelMessage(MIDIMsgNoteOn, Channel, Key, Velocity);
|
|||
|
|
Include(FActiveNotes[Channel], Key);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendPolyphonicKeyPressure(Channel: TMIDIChannel;
|
|||
|
|
Key: TMIDINote; Value: TMIDIDataByte);
|
|||
|
|
begin
|
|||
|
|
SendChannelMessage(MIDIMsgPolyKeyPressure, Channel, Key, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendControlChange(Channel: TMIDIChannel; ControllerNum, Value: TMIDIDataByte);
|
|||
|
|
begin
|
|||
|
|
SendChannelMessage(MIDIMsgControlChange, Channel, ControllerNum, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendControlChangeHR(Channel: TMIDIChannel; ControllerNum: TMIDIDataByte;
|
|||
|
|
Value: TMIDIDataWord);
|
|||
|
|
begin
|
|||
|
|
SendControlChange(Channel, ControllerNum, Value shr BitsPerMIDIDataByte and MIDIDataMask);
|
|||
|
|
if ControllerNum <= $13 then
|
|||
|
|
SendControlChange(Channel, ControllerNum or $20, Value and MIDIDataMask);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendSwitchChange(Channel: TMIDIChannel; ControllerNum: TMIDIDataByte; Value: Boolean);
|
|||
|
|
const
|
|||
|
|
DataByte: array [Boolean] of Byte = ($00, $7F);
|
|||
|
|
begin
|
|||
|
|
SendChannelMessage(MIDIMsgControlChange, Channel, ControllerNum, DataByte[Value]);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendProgramChange(Channel: TMIDIChannel; ProgramNum: TMIDIDataByte);
|
|||
|
|
begin
|
|||
|
|
SendChannelMessage(MIDIMsgProgramChange, Channel, ProgramNum, 0);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendChannelPressure(Channel: TMIDIChannel; Value: TMIDIDataByte);
|
|||
|
|
begin
|
|||
|
|
SendChannelMessage(MIDIMsgChannelKeyPressure, Channel, Value, 0);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendPitchWheelChange(Channel: TMIDIChannel; Value: TMIDIDataWord);
|
|||
|
|
begin
|
|||
|
|
SendChannelMessage(MIDIMsgPitchWheelChange, Channel, Value and MidiDataMask, Value shr BitsPerMIDIDataByte);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendPitchWheelPos(Channel: TMIDIChannel; Value: Single);
|
|||
|
|
var
|
|||
|
|
Temp: TMIDIDataWord;
|
|||
|
|
begin
|
|||
|
|
if Value < 0 then
|
|||
|
|
Temp := Round(Value * (1 shl 13))
|
|||
|
|
else
|
|||
|
|
Temp := Round(Value * (1 shl 13 - 1));
|
|||
|
|
SendPitchWheelChange(Channel, Temp);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SwitchAllSoundOff(Channel: TMIDIChannel);
|
|||
|
|
begin
|
|||
|
|
SendControlChange(Channel, MIDICCAllSoundOff, 0);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SwitchLocalControl(Channel: TMIDIChannel; Value: Boolean);
|
|||
|
|
begin
|
|||
|
|
SendSwitchChange(Channel, MIDICCLocalControl, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.ResetAllControllers(Channel: TMIDIChannel);
|
|||
|
|
begin
|
|||
|
|
SendControlChange(Channel, MIDICCResetAllControllers, 0);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SwitchAllNotesOff(Channel: TMIDIChannel);
|
|||
|
|
begin
|
|||
|
|
CheckMIDIChannelNum(Channel);
|
|||
|
|
SendControlChange(Channel, MIDICCAllNotesOff, 0);
|
|||
|
|
FActiveNotes[Channel] := [];
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SetRunningStatusEnabled(const Value: Boolean);
|
|||
|
|
begin
|
|||
|
|
FMIDIStatus := MIDIInvalidStatus;
|
|||
|
|
FRunningStatusEnabled := Value;
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendSingleNoteTuningChange(const TargetDeviceID, TuningProgramNum: TMidiDataByte;
|
|||
|
|
const TuningData: array of TSingleNoteTuningData);
|
|||
|
|
var
|
|||
|
|
BufSize, Count: Integer;
|
|||
|
|
Buf: array of Byte;
|
|||
|
|
begin
|
|||
|
|
Count := High(TuningData) - Low(TuningData) + 1;
|
|||
|
|
BufSize := 8 + Count * SizeOf(TSingleNoteTuningData);
|
|||
|
|
SetLength(Buf, BufSize);
|
|||
|
|
Buf[0] := MIDIMsgSysEx; // Universal Real Time SysEx header, first byte
|
|||
|
|
Buf[1] := $7F; // second byte
|
|||
|
|
Buf[2] := TargetDeviceID; // ID of target device (?)
|
|||
|
|
Buf[3] := 8; // sub-ID#1 (MIDI Tuning)
|
|||
|
|
Buf[4] := 2; // sub-ID#2 (note change)
|
|||
|
|
Buf[5] := TuningProgramNum; // tuning program number (0 <20> 127)
|
|||
|
|
Buf[6] := Count;
|
|||
|
|
Move(TuningData, Buf[7], Count * SizeOf(TSingleNoteTuningData));
|
|||
|
|
Buf[BufSize - 1] := MIDIMsgEOX;
|
|||
|
|
SendMessage(Buf);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SwitchActiveNotesOff(Channel: TMIDIChannel);
|
|||
|
|
var
|
|||
|
|
Note: TMIDINote;
|
|||
|
|
begin
|
|||
|
|
CheckMIDIChannelNum(Channel);
|
|||
|
|
if FActiveNotes[Channel] <> [] then
|
|||
|
|
for Note := Low(Note) to High(Note) do
|
|||
|
|
if Note in FActiveNotes[Channel] then
|
|||
|
|
SendNoteOff(Channel, Note, $7F);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SwitchActiveNotesOff;
|
|||
|
|
var
|
|||
|
|
Channel: TMIDIChannel;
|
|||
|
|
begin
|
|||
|
|
for Channel := Low(Channel) to High(Channel) do
|
|||
|
|
SwitchActiveNotesOff(Channel);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SelectProgram(Channel: TMIDIChannel;
|
|||
|
|
BankNum: TMIDIDataWord; ProgramNum: TMIDIDataByte);
|
|||
|
|
begin
|
|||
|
|
SendControlChangeHR(Channel, MIDICCBankSelect, BankNum);
|
|||
|
|
SendProgramChange(Channel, ProgramNum);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendMessage(const Data: array of Byte);
|
|||
|
|
begin
|
|||
|
|
if IsRunningStatus(Data[0]) then
|
|||
|
|
{$IFDEF FPC}
|
|||
|
|
DoSendMessage(PJclByteArray(@Data[1])^)
|
|||
|
|
{$ELSE}
|
|||
|
|
DoSendMessage(Slice(Data, 1))
|
|||
|
|
{$ENDIF FPC}
|
|||
|
|
else
|
|||
|
|
DoSendMessage(Data);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
function TJclMIDIOut.GetMIDIStatus: TMIDIStatusByte;
|
|||
|
|
begin
|
|||
|
|
Result := FMIDIStatus;
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
function TJclMIDIOut.IsRunningStatus(StatusByte: TMIDIStatusByte): Boolean;
|
|||
|
|
begin
|
|||
|
|
Result := (StatusByte = FMIDIStatus) and
|
|||
|
|
((StatusByte and $F0) <> $F0) and // is channel message
|
|||
|
|
RunningStatusEnabled;
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendBalanceChange(Channel: TMIDIChannel; Value: TMidiDataByte);
|
|||
|
|
begin
|
|||
|
|
SendControlChange(Channel, MIDICCBalance, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendBalanceChangeHR(Channel: TMIDIChannel; Value: TMidiDataWord);
|
|||
|
|
begin
|
|||
|
|
SendControlChangeHR(Channel, MIDICCBalance, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendBreathControlChange(Channel: TMIDIChannel; Value: TMidiDataByte);
|
|||
|
|
begin
|
|||
|
|
SendControlChange(Channel, MIDICCBreathControl, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendBreathControlChangeHR(Channel: TMIDIChannel; Value: TMidiDataWord);
|
|||
|
|
begin
|
|||
|
|
SendControlChangeHR(Channel, MIDICCBreathControl, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendDataEntry(Channel: TMIDIChannel; Value: TMidiDataByte);
|
|||
|
|
begin
|
|||
|
|
SendControlChange(Channel, MIDICCDataEntry, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendDataEntryHR(Channel: TMIDIChannel; Value: TMidiDataWord);
|
|||
|
|
begin
|
|||
|
|
SendControlChangeHR(Channel, MIDICCDataEntry, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendExpressionChange(Channel: TMIDIChannel; Value: TMidiDataByte);
|
|||
|
|
begin
|
|||
|
|
SendControlChange(Channel, MIDICCExpression, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendExpressionChangeHR(Channel: TMIDIChannel; Value: TMidiDataWord);
|
|||
|
|
begin
|
|||
|
|
SendControlChangeHR(Channel, MIDICCExpression, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendFootControllerChange(Channel: TMIDIChannel; Value: TMidiDataByte);
|
|||
|
|
begin
|
|||
|
|
SendControlChange(Channel, MIDICCFootController, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendFootControllerChangeHR(Channel: TMIDIChannel; Value: TMidiDataWord);
|
|||
|
|
begin
|
|||
|
|
SendControlChangeHR(Channel, MIDICCFootController, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SwitchHold2(Channel: TMIDIChannel; Value: Boolean);
|
|||
|
|
begin
|
|||
|
|
SendSwitchChange(Channel, MIDICCHold2, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SwitchLegato(Channel: TMIDIChannel; Value: Boolean);
|
|||
|
|
begin
|
|||
|
|
SendSwitchChange(Channel, MIDICCLegato, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendChannelVolumeChange(Channel: TMIDIChannel;
|
|||
|
|
Value: TMidiDataByte);
|
|||
|
|
begin
|
|||
|
|
SendControlChange(Channel, MIDICCChannelVolume, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendChannelVolumeChangeHR(Channel: TMIDIChannel;
|
|||
|
|
Value: TMidiDataWord);
|
|||
|
|
begin
|
|||
|
|
SendControlChangeHR(Channel, MIDICCChannelVolume, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendModulationWheelChange(Channel: TMIDIChannel;
|
|||
|
|
Value: TMidiDataByte);
|
|||
|
|
begin
|
|||
|
|
SendControlChange(Channel, MIDICCModulationWheel, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendModulationWheelChangeHR(Channel: TMIDIChannel; Value: TMidiDataWord);
|
|||
|
|
begin
|
|||
|
|
SendControlChangeHR(Channel, MIDICCModulationWheel, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendPanChange(Channel: TMIDIChannel; Value: TMidiDataByte);
|
|||
|
|
begin
|
|||
|
|
SendControlChange(Channel, MIDICCPan, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendPanChangeHR(Channel: TMIDIChannel; Value: TMidiDataWord);
|
|||
|
|
begin
|
|||
|
|
SendControlChangeHR(Channel, MIDICCPan, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SwitchPortamento(Channel: TMIDIChannel; Value: Boolean);
|
|||
|
|
begin
|
|||
|
|
SendSwitchChange(Channel, MIDICCPortamento, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendPortamentoTimeChange(Channel: TMIDIChannel;
|
|||
|
|
Value: TMidiDataByte);
|
|||
|
|
begin
|
|||
|
|
SendControlChange(Channel, MIDICCPortamentoTime, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SendPortamentoTimeChangeHR(Channel: TMIDIChannel;
|
|||
|
|
Value: TMidiDataWord);
|
|||
|
|
begin
|
|||
|
|
SendControlChangeHR(Channel, MIDICCPortamentoTime, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SwitchSoftPedal(Channel: TMIDIChannel; Value: Boolean);
|
|||
|
|
begin
|
|||
|
|
SendSwitchChange(Channel, MIDICCSoftPedal, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SwitchSustain(Channel: TMIDIChannel; Value: Boolean);
|
|||
|
|
begin
|
|||
|
|
SendSwitchChange(Channel, MIDICCSustain, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SwitchSostenuto(Channel: TMIDIChannel; Value: Boolean);
|
|||
|
|
begin
|
|||
|
|
SendSwitchChange(Channel, MIDICCSustenuto, Value);
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SwitchOmniModeOff(Channel: TMIDIChannel);
|
|||
|
|
begin
|
|||
|
|
SendControlChange(Channel, MIDICCOmniModeOff, 0);
|
|||
|
|
FActiveNotes[Channel] := []; // implicit All Notes Off
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SwitchOmniModeOn(Channel: TMIDIChannel);
|
|||
|
|
begin
|
|||
|
|
SendControlChange(Channel, MIDICCOmniModeOn, 0);
|
|||
|
|
FActiveNotes[Channel] := []; // implicit All Notes Off
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SwitchMonoModeOn(Channel: TMIDIChannel; ChannelCount: Integer);
|
|||
|
|
begin
|
|||
|
|
SendControlChange(Channel, MIDICCMonoModeOn, ChannelCount);
|
|||
|
|
FActiveNotes[Channel] := []; // implicit All Notes Off
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
procedure TJclMIDIOut.SwitchPolyModeOn(Channel: TMIDIChannel);
|
|||
|
|
begin
|
|||
|
|
SendControlChange(Channel, MIDICCPolyModeOn, 0);
|
|||
|
|
FActiveNotes[Channel] := []; // implicit All Notes Off
|
|||
|
|
end;
|
|||
|
|
|
|||
|
|
// History:
|
|||
|
|
|
|||
|
|
// $Log: JclMIDI.pas,v $
|
|||
|
|
// Revision 1.13 2005/08/07 13:09:54 outchy
|
|||
|
|
// Changed PByteArray to PJclByteArray to avoid RangeCheck exceptions.
|
|||
|
|
//
|
|||
|
|
// Revision 1.12 2005/03/08 08:33:17 marquardt
|
|||
|
|
// overhaul of exceptions and resourcestrings, minor style cleaning
|
|||
|
|
//
|
|||
|
|
// Revision 1.11 2005/02/24 16:34:40 marquardt
|
|||
|
|
// remove divider lines, add section lines (unfinished)
|
|||
|
|
//
|
|||
|
|
// Revision 1.10 2004/10/12 18:29:52 rrossmair
|
|||
|
|
// cleanup
|
|||
|
|
//
|
|||
|
|
// Revision 1.9 2004/08/03 07:22:37 marquardt
|
|||
|
|
// resourcestring cleanup
|
|||
|
|
//
|
|||
|
|
// Revision 1.8 2004/07/28 18:00:50 marquardt
|
|||
|
|
// various style cleanings, some minor fixes
|
|||
|
|
//
|
|||
|
|
// Revision 1.7 2004/06/16 07:30:27 marquardt
|
|||
|
|
// added tilde to all IFNDEF ENDIFs, inherited qualified
|
|||
|
|
//
|
|||
|
|
// Revision 1.6 2004/06/07 04:27:07 rrossmair
|
|||
|
|
// "Not implemented" error for Unix added as placeholder.
|
|||
|
|
//
|
|||
|
|
// Revision 1.5 2004/05/05 00:09:59 mthoma
|
|||
|
|
// Updated headers: Added donors as contributors, adjusted the initial authors, added cvs names when they were not obvious. Changed $data to $date where necessary,
|
|||
|
|
//
|
|||
|
|
|
|||
|
|
end.
|