home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Garbo
/
Garbo.cdr
/
mac
/
sound
/
chaneler.sit
/
Channelizer.ƒ
/
MungeMidi.p
< prev
next >
Wrap
Text File
|
1989-09-08
|
10KB
|
343 lines
unit MungeMidi;
{ Copyright ⌐ 1989 Chris Muir, Entropy Engineering. }
{ Internet: (hplabs,pacbell,ucbvax,apple) !well!cbm }
{ Pan: ZMS }
{ US Mail: 360 Elizabeth St. San Francisco, CA 94114 }
{ ### Channeler. Forces all MIDI input to be on one output channel. ### }
{ 1.0 ╩August 17, 1989 cbm }
interface
uses
Midi; { QuickDraw, ToolIntf, WindowLayout, }
procedure InitMyMidi;
procedure UnInitMyMidi;
var
gClockMIDIRefNum: integer;
gInMIDIRefNum: integer;
gOutMIDIRefNum: integer;
gTheOutChannel: integer;
gErrorPacket: MIDIPacket;
gMMVersion: longint;
gMidiOutChanNum: integer; { MIDI output chan. Needs to be set externally. 0-16 range. }
const
kDratDialog = 10;
{ Needs a dialog of this number in resource file. }
{ Dialog should have a button as item 1, and 3 static text items (^0,^1,^2) }
I_Drat = 1; { Dialog 'cancel' button }
implementation
var
pOutPacket: MIDIPacket;
pOutPacketPtr: MIDIPacketPtr;
const
kMMPacketHeadLen = 6; { subtract this from the MM len byte to get # of data bytes. }
kMMSig = 'mChn'; { our MM Signature (and application signature) }
{ *Ñ*Ñ*Ñ*Ñ*Ñ*Ñ*Ñ*Ñ* Some Midi Equates *Ñ*Ñ*Ñ*Ñ*Ñ*Ñ*Ñ*Ñ* }
{ If a midi status byte (data[0]) is shifted right 4 and masked with 7, }
{the 3 lsbs that are left ╥tell the tale╙. Like this:}
{Ñ CommandType := BitShift(ByteInQuestion, -4);Ñ}
{Ñ CommandType := BitAnd(CommandType, $07);Ñ}
{These are the constants for use with a case statement on CommandType (the 3 lsbs above). }
C_NoteOff = 0;
C_NoteOn = 1;
C_PolyKey = 2;
C_Control = 3;
C_Prog = 4;
C_Pressure = 5;
C_Bend = 6;
C_Sys = 7;
M_StatMask = $80; { BitAnd w/ byte in question to determine if a status byte }
M_ChanMask = $0F; { BitAnd w/ byte in question to isolate channel nibble }
M_NoChanMask = $F0; { BitAnd w/ byte in question to wipe channel nibble }
M_ContSwStart = 64; { the first switch continous controller }
M_ContSwStop = 95; { the last switch continous controller }
M_ContContStop = 120; { the last continous controller }
{ Channel Mode Messages }
M_ResetControllers = 121;
M_LocalControl = 122;
M_AllNotesOff = 123;
M_OmniOff = 124;
M_OmniOn = 125;
M_MonoOn = 126;
M_PolyOn = 127;
M_SysEx = $F0; { }
M_SongPointer = $F2; { }
M_SongSelect = $F3; { }
M_TuneReq = $F6; { }
M_EOX = $F7; { }
M_Clock = $F8; { }
M_Start = $FA; { }
M_Continue = $FB; { }
M_Stop = $FC; { }
M_ActiveSense = $FE; { }
M_Reset = $FF; { }
ForceOff = $10; { Subtract from a note-on w/ Velo=0 to make a note-off }
StatToZero = 127; { subtract this from a status byte to make it zero-based }
EndNotes = 33; { the first non-NoteOn / NoteOff byte }
function SetA5 (newA5: LONGINT): LONGINT;
inline { returns some partition's A5, and sets A5 to newA5 }
$2F4D, $0004, $2A5F;
procedure YodelMidiErr (Msg1, Msg2, Msg3: str255);
forward;
{_____________________ CheckMidiManErr _____________________}
{$D-}
procedure CheckMidiManErr (myOops: OsErr; theRoutine: str255; BadPacket: MIDIPacketPtr);
var
theErrStr: str255;
ohMy: str255;
begin
if myOops <> noErr then
begin
{ we can't do much in the way of reporting at interrupt time. }
{ this is pretty fragile. }
gErrorPacket := BadPacket^; { put bad packet into a global }
DebugStr(theRoutine); { and crash into MacsBug, TMON, etc. }
end;
end;
{$D+}
{_____________________ YodelMidiErr _____________________}
procedure YodelMidiErr (Msg1, Msg2, Msg3: str255);
var
thisDialog: DialogPtr;
exitDialog: boolean;
tempRect: Rect;
dType: Integer;
dItem: Handle;
itemHit: Integer;
begin
begin
thisDialog := GetNewDialog(kDratDialog, nil, Pointer(-1));
paramText(Msg1, Msg2, Msg3, ''); { Speak }
ShowWindow(thisDialog);
SelectWindow(thisDialog); { Let's see it }
exitDialog := false;
repeat
ModalDialog(nil, itemHit);
GetDItem(thisDialog, itemHit, dType, dItem, tempRect); { what was touched? }
if (ItemHit = I_Drat) then
begin
exitDialog := true;
end;
until exitDialog;
DisposDialog(thisDialog);
end; { dialog handler }
end; { YodelMidiErr }
{_____________________ MyMidiInput _____________________}
{$D-}
{ This is our Readhook. Called at interrupt time. Be careful.}
function MyMidiInput (myPacket: MIDIPacketPtr; myRefCon: LONGINT): integer;
var
packetType: longint;
oldA5: longint;
passOut: MIDIPacketPtr;
theStatusByte: byte;
theStatusCom: byte;
theCom: byte;
theByte: byte;
begin
oldA5 := SetA5(myRefCon);
packetType := BAND(myPacket^.flags, midiTypeMask);
if (packetType = midiMsgType) & (myPacket^.data[0] <> 0) then
begin { good packet }
pOutPacket := myPacket^; { copy packet }
pOutPacketPtr := @pOutPacket; { set pointer to copied packet }
theStatusByte := pOutPacket.data[0]; { grab the status byte }
theCom := BitShift(theStatusByte, -4); { create the index }
theCom := BitAnd(theCom, $07);
case theCom of
C_NoteOff, C_NoteOn, C_PolyKey, C_Prog, C_Pressure, C_Control, C_Bend:
begin
theStatusCom := BAND(theStatusByte, M_NoChanMask); { wipe old chan }
theStatusByte := BOR(theStatusCom, gMidiOutChanNum); { OR in new chan }
pOutPacket.data[0] := theStatusByte; { and stash it }
end;
C_Sys:
begin { just pass system messages }
end;
otherwise
begin { there really can't be an otherwise, but╔ }
end;
end; { case theCom }
CheckMidiManErr(MIDIWritePacket(gOutMIDIRefNum, pOutPacketPtr), 'MyMidiInput.write', @pOutPacketPtr);
end { if (packetType = midiMsgType) & (myPacket^.data[0] <> 0) }
else
begin { if (packetType <> midiMsgType) | (myPacket^.data[0] = 0) }
{ we have a bogus packet }
CheckMidiManErr(-1, 'MyMidiInput.read', @pOutPacketPtr);
end;
MyMidiInput := midiMorePacket; { ask for more }
oldA5 := SetA5(oldA5); { restore pre-interrupt A5 }
end; { MyMidiInput }
{$D+}
{_____________________ InitMyMidi _____________________}
procedure InitMyMidi;
const
CurA5 = $904;
var
tempRect: rect;
myOops: OsErr;
myIcon: Handle;
myMidiClkInfo: MIDIClkInfo;
myMidiClockParams: MIDIPortParams;
myMidiInputParams: MIDIPortParams;
myMidiOutputParams: MIDIPortParams;
theErrStr: str255;
begin
myIcon := Get1Resource('ICN#', 128); { our applications ICN# }
gMMVersion := SndDispVersion(midiToolNum); { are we here? }
if gMMVersion = 0 then
begin { oops }
YodelMidiErr('Midi Manager Not Present', '', '');
end;
myOops := MidiSignIn(kMMSig, 0, myIcon, 'Channeler');
begin { add the Clock Port, not used by Channeler. Example only. }
myMidiClkInfo.sync := midiInternalSync;
myMidiClkInfo.curTime := 0;
myMidiClkInfo.format := midiFormatMSec;
myMidiClockParams.portID := 'Clk '; { it has to have a name. }
myMidiClockParams.portType := midiPortTypeTimeInv; { invisable, for an internal time base only }
myMidiClockParams.timeBase := 0; { this IS the time base }
myMidiClockParams.offsetTime := 0; { start at the begining }
myMidiClockParams.readHook := nil; { }
myMidiClockParams.refCon := Ord4(handle(CurA5)^); { our A5, so we can find our globals @ Interrupt time }
myMidiClockParams.initClock := myMidiClkInfo;
myMidiClockParams.name := '';
myOops := MIDIAddPort(kMMSig, 2048, gClockMIDIRefNum, @myMidiClockParams);
if myOops <> noErr then
if myOops = midiVConnectMade then
begin
end
else if myOops = midiVConnectErr then
begin
end
else
begin
NumToString(myOops, theErrStr);
YodelMidiErr('Midi Manager Error#', theErrStr, ' while doing MIDIAddPort (time)');
end;
MIDIStartTime(gClockMIDIRefNum); { this program doesn't use time, but let's start it anyway }
end; { add the Clock Port }
begin { add the Input Port }
myMidiInputParams.portID := 'In ';
myMidiInputParams.portType := midiPortTypeInput;
myMidiInputParams.timeBase := gClockMIDIRefNum;
myMidiInputParams.offsetTime := 0;
myMidiInputParams.readHook := @MyMidiInput;
myMidiInputParams.refCon := Ord4(handle(CurA5)^);
myMidiInputParams.initClock := myMidiClkInfo;
myMidiInputParams.name := '';
myOops := MIDIAddPort(kMMSig, 2048, gInMIDIRefNum, @myMidiInputParams);
if myOops <> noErr then
if myOops = midiVConnectMade then
begin
end
else if myOops = midiVConnectErr then
begin
{ the MM had a virtual patch pending. It's not really an error. }
end
else
begin
NumToString(myOops, theErrStr);
YodelMidiErr('Midi Manager Error#', theErrStr, ' while doing MIDIAddPort (input)');
end;
end; { add the Input Port }
begin { add the Output Port }
myMidiOutputParams.portID := 'Out ';
myMidiOutputParams.portType := midiPortTypeOutput;
myMidiOutputParams.timeBase := gClockMIDIRefNum;
myMidiOutputParams.offsetTime := 0;
myMidiOutputParams.readHook := nil;
myMidiOutputParams.refCon := 0;
myMidiOutputParams.initClock := myMidiClkInfo;
myMidiOutputParams.name := '';
myOops := MIDIAddPort(kMMSig, 2048, gOutMIDIRefNum, @myMidiOutputParams);
if myOops <> noErr then
if myOops = midiVConnectMade then
begin
end
else if myOops = midiVConnectErr then
begin
end
else
begin
NumToString(myOops, theErrStr);
YodelMidiErr('Midi Manager Error#', theErrStr, ' while doing MIDIAddPort (output) ');
end;
end; { add the Output Port }
gMidiOutChanNum := 0;
new(pOutPacketPtr);
end; { InitMyMidi }
{_____________________ UnInitMyMidi _____________________}
procedure UnInitMyMidi;
begin
MidiSignOut(kMMSig);
end; { UnInitMyMidi }
end.