📄 jclwinmidi.pas
字号:
{**************************************************************************************************}
{ }
{ 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 JclWinMidi.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 }
{ }
{**************************************************************************************************}
{ }
{ MIDI functions for MS Windows platform }
{ }
{ Unit owner: Robert Rossmair }
{ }
{**************************************************************************************************}
// Last modified: $Date: 2005/02/25 07:20:16 $
// For history see end of file
unit JclWinMidi;
{$I jcl.inc}
{$I windowsonly.inc}
interface
uses
SysUtils, Classes, Windows, MMSystem,
JclMIDI;
type
TStereoChannel = (scLeft, scRight);
// MIDI Out
IJclWinMidiOut = interface(IJclMidiOut)
['{F3FCE71C-B924-462C-BA0D-8C2DC118DADB}']
// property access methods
function GetChannelVolume(Channel: TStereoChannel): Word;
procedure SetChannelVolume(Channel: TStereoChannel; const Value: Word);
function GetVolume: Word;
procedure SetVolume(const Value: Word);
// properties
property ChannelVolume[Channel: TStereoChannel]: Word read GetChannelVolume write SetChannelVolume;
property Volume: Word read GetVolume write SetVolume;
end;
function MidiOut(DeviceID: Cardinal): IJclWinMidiOut;
procedure GetMidiOutputs(const List: TStrings);
procedure MidiOutCheck(Code: MMResult);
// MIDI In
procedure MidiInCheck(Code: MMResult);
implementation
uses
JclResources, JclStrings;
var
FMidiOutputs: TStringList = nil;
function MidiOutputs: TStrings;
var
I: Integer;
Caps: MIDIOUTCAPS;
begin
if FMidiOutputs = nil then
begin
FMidiOutputs := TStringList.Create;
for I := 0 to midiOutGetNumDevs - 1 do
begin
if (midiOutGetDevCaps(I, @Caps, SizeOf(Caps)) = MMSYSERR_NOERROR) then
FMidiOutputs.Add(Caps.szPName);
end;
end;
Result := FMidiOutputs;
end;
procedure GetMidiOutputs(const List: TStrings);
begin
List.Assign(MidiOutputs);
end;
function GetMidiInErrorMessage(const ErrorCode: MMRESULT): string;
begin
SetLength(Result, MAXERRORLENGTH-1);
if midiInGetErrorText(ErrorCode, @Result[1], MAXERRORLENGTH) = MMSYSERR_NOERROR then
StrResetLength(Result)
else
Result := Format(RsMidiInUnknownError, [ErrorCode]);
end;
function GetMidiOutErrorMessage(const ErrorCode: MMRESULT): string;
begin
SetLength(Result, MAXERRORLENGTH-1);
if midiOutGetErrorText(ErrorCode, @Result[1], MAXERRORLENGTH) = MMSYSERR_NOERROR then
StrResetLength(Result)
else
Result := Format(RsMidiOutUnknownError, [ErrorCode]);
end;
procedure MidiInCheck(Code: MMResult);
begin
if Code <> MMSYSERR_NOERROR then
raise EJclMidiError.Create(GetMidiInErrorMessage(Code));
end;
procedure MidiOutCheck(Code: MMResult);
begin
if Code <> MMSYSERR_NOERROR then
raise EJclMidiError.Create(GetMidiOutErrorMessage(Code));
end;
//=== { TMidiOut } ===========================================================
type
TMidiOut = class(TJclMidiOut, IJclWinMidiOut)
private
FHandle: HMIDIOUT;
FDeviceID: Cardinal;
FDeviceCaps: MIDIOUTCAPS;
FVolume: DWord;
function GetChannelVolume(Channel: TStereoChannel): Word;
procedure SetChannelVolume(Channel: TStereoChannel; const Value: Word);
function GetVolume: Word;
procedure SetVolume(const Value: Word);
procedure SetLRVolume(const LeftValue, RightValue: Word);
protected
function GetName: string; override;
procedure LongMessage(const Data: array of Byte);
procedure DoSendMessage(const Data: array of Byte); override;
public
constructor Create(ADeviceID: Cardinal);
destructor Destroy; override;
property DeviceID: Cardinal read FDeviceID;
property Name: string read GetName;
property ChannelVolume[Channel: TStereoChannel]: Word read GetChannelVolume write SetChannelVolume;
property Volume: Word read GetVolume write SetVolume;
end;
var
MidiMapperDeviceID: Cardinal = MIDI_MAPPER;
function MidiOut(DeviceID: Cardinal): IJclWinMidiOut;
var
Device: TMidiOut;
begin
if DeviceID = MIDI_MAPPER then
DeviceID := MidiMapperDeviceID;
Device := nil;
if DeviceID <> MIDI_MAPPER then
Device := TMidiOut(MidiOutputs.Objects[DeviceID]);
// make instance a singleton for a given device ID
if not Assigned(Device) then
begin
Device := TMidiOut.Create(DeviceID);
if DeviceID = MIDI_MAPPER then
MidiMapperDeviceID := Device.DeviceID;
// cannot use DeviceID argument as index here, since it might be MIDI_MAPPER
MidiOutputs.Objects[Device.DeviceID] := Device;
end;
Result := Device;
end;
constructor TMidiOut.Create(ADeviceID: Cardinal);
begin
inherited Create;
FVolume := $FFFFFFFF; // max. volume, in case Get/SetChannelVolume not supported
MidiOutCheck(midiOutGetDevCaps(ADeviceID, @FDeviceCaps, SizeOf(FDeviceCaps)));
MidiOutCheck(midiOutOpen(@FHandle, ADeviceID, 0, 0, 0));
MidiOutCheck(midiOutGetID(FHandle, @FDeviceID));
end;
destructor TMidiOut.Destroy;
begin
inherited Destroy;
midiOutClose(FHandle);
MidiOutputs.Objects[FDeviceID] := nil;
end;
function TMidiOut.GetName: string;
begin
Result := FDeviceCaps.szPName;
end;
procedure TMidiOut.LongMessage(const Data: array of Byte);
var
Hdr: MIDIHDR;
begin
FillChar(Hdr, SizeOf(Hdr), 0);
Hdr.dwBufferLength := High(Data) - Low(Data) + 1;;
Hdr.dwBytesRecorded := Hdr.dwBufferLength;
Hdr.lpData := @Data;
Hdr.dwFlags := 0;
MidiOutCheck(midiOutPrepareHeader(FHandle, @Hdr, SizeOf(Hdr)));
MidiOutCheck(midiOutLongMsg(FHandle, @Hdr, SizeOf(Hdr)));
repeat until (Hdr.dwFlags and MHDR_DONE) <> 0;
end;
procedure TMidiOut.DoSendMessage(const Data: array of Byte);
var
I: Integer;
Msg: packed record
case Integer of
0:
(Bytes: array [0..2] of Byte);
1:
(DWord: LongWord);
end;
begin
if High(Data) < 3 then
begin
for I := 0 to High(Data) do
Msg.Bytes[I] := Data[I];
MidiOutCheck(midiOutShortMsg(FHandle, Msg.DWord));
end
else LongMessage(Data);
end;
function TMidiOut.GetChannelVolume(Channel: TStereoChannel): Word;
begin
midiOutGetVolume(FHandle, @FVolume);
Result := FVolume;
end;
procedure TMidiOut.SetChannelVolume(Channel: TStereoChannel; const Value: Word);
begin
if Channel = scLeft then
SetLRVolume(Value, ChannelVolume[scRight])
else
SetLRVolume(ChannelVolume[scLeft], Value);
end;
function TMidiOut.GetVolume: Word;
begin
Result := GetChannelVolume(scLeft);
end;
procedure TMidiOut.SetVolume(const Value: Word);
begin
SetLRVolume(Value, Value);
end;
procedure TMidiOut.SetLRVolume(const LeftValue, RightValue: Word);
var
Value: DWord;
begin
with LongRec(Value) do
begin
Lo := LeftValue;
Hi := RightValue;
end;
if Value <> FVolume then
begin
if (MIDICAPS_VOLUME and FDeviceCaps.dwSupport) <> 0 then
MidiOutCheck(midiOutSetVolume(FHandle, Value));
FVolume := Value;
end;
end;
initialization
finalization
FreeAndNil(FMidiOutputs);
// History:
// $Log: JclWinMIDI.pas,v $
// Revision 1.13 2005/02/25 07:20:16 marquardt
// add section lines
//
// Revision 1.12 2005/02/24 16:34:53 marquardt
// remove divider lines, add section lines (unfinished)
//
// Revision 1.11 2004/10/17 21:00:16 mthoma
// cleaning
//
// Revision 1.10 2004/07/31 06:21:03 marquardt
// fixing TStringLists, adding BeginUpdate/EndUpdate, finalization improved
//
// Revision 1.9 2004/07/28 18:00:55 marquardt
// various style cleanings, some minor fixes
//
// Revision 1.8 2004/06/16 07:30:31 marquardt
// added tilde to all IFNDEF ENDIFs, inherited qualified
//
// Revision 1.7 2004/06/14 11:05:53 marquardt
// symbols added to all ENDIFs and some other minor style changes like removing IFOPT
//
// Revision 1.6 2004/05/05 07:33:49 rrossmair
// header updated according to new policy: initial developers & contributors listed
//
// Revision 1.5 2004/04/06 04:55:18
// adapt compiler conditions, add log entry
//
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -