TweetFollow Us on Twitter

Mac II Midi Demo
Volume Number:3
Issue Number:12
Column Tag:The Midi Mac

A Midi Demo for the Mac II

By Kirk Austin, Contributing Editor, San Rafael, CA

Here we are back in MIDI land again. This is a continuation of the July 1987 article in which we bacame familiar with what MIDI is all about, and looked into some of the low level routines that are necessary to work with MIDI on the Macintosh.

Now, probably what I didn’t tell you last time was that these low level routines were designed to work with LightSpeed Pascal from Think Technologies. I have found that this is the easiest development system for people just starting to program the Macintosh because of its unique source level debugging features. Also, I have found the Pascal language to be the best choice among languages available for the Macintosh because the Macintosh was designed with the Pascal language in mind. Because of this all of the documentation is written with a Pascal syntax (Inside Macintosh, Macintosh Revealed, etc.).

As a result of this built-in bias, if any other language than Pascal is chosen as a development tool, a great deal of time is typically spent just translating from the Pascal documentation to whatever language you have decided to use. The moral of the story is, if you are just starting out programming the Macintosh, you would be doing yourself a big favor by choosing Pascal as your development language, ‘nuff said.

The Apple Music Fair

On July 10th Apple had an in-house party to let its employees find out more about music programs for the Macintosh. It was a great party, with food and drinks in the courtyard of the DeAnza 3 building. About a dozen or so companies with music products for the Macintosh were present, showing their wares, and there was even a presentation by Alan Kay on the future of computers and music.

I was impressed by the fact that Apple is making an effort to get its employees excited about the musical possibilities of the Macintosh computer. The Mac has become the defacto standard for MIDI controllers. If you attend one of the biannual NAMM shows (which is where all of the new musical products are exhibited) you will find that the Macintosh has taken over as far as musical computers go. I just wish Apple would go a little bit further with their support of MIDI. For instance, I know that there are MIDI routines built into the new ROM’s on the Macintosh II, but I can’t get anyone at Apple to tell me what they are. Now, obviously, someone there knows what the routines are, after all, someone had to write them in the first place, right? But, for some reason, Apple is not releasing the information just yet. I hope this changes soon, as I would like to be using ROM routines instead of having to write all of my own code, but I guess I will just have to wait a while (sigh).

By the way, I heard that copies of the July issue of MacTutor are making the rounds at Apple and I have gotten inquiries about the MIDI routines from some Apple employees. Maybe I can stir up enough interest at Apple to get them to come through with some information (are you listening, guys?).

Whoops!

Unfortunately, there was a slight oversight on my part in the program listings that were printed in July that caused a bug in the interrupt handlers. If you are using the low level routines in a program that uses input from the Macintosh keyboard, the status register can become corrupted by the MIDI interrupt routines and the computer will think that it is getting a never-ending string of keystrokes from the ASCII keyboard. I get a string of lower case “c”, but othere people have reported getting lower case “s”.

Anyway, the problem is that I neglected to save and restore the status register in the interrupt routines, so you need to add the following two lines to the four interrupt handlers (i.e. TxIntHandA, TxIntHandB, RxIntHandA, and RxIntHandB):

This should be the first line at the beginning of each routine:

 MOVE  SR,-(SP)

then, replace the line

 ANDI  #$F8FF,SR

at the end of each interrupt handler with the following line

 MOVE  (SP)+,SR

This change keeps the status register intact instead of changing its value after the interrupt routine has executed. Sorry if this error has caused anyone a great deal of hair pulling.

New Changes to LLMIDI

There are also a couple of additional routines that I have added to the library since it was published. The revised routine library is available on the source code disk for July, so if you just buy that you will save yourself an awful lot of typing. Also, there is the distinct possibility that if you do type the listings in yourself that you will make a typo and it will get flagged as an assembly error. The listings on the source code disk have been assembled with MDS without any errors being flagged, so if you are showing an error it is probably a typo.

Anyway, the new additions to the library have to do with filtering out “active sensing” MIDI bytes from the data stream, and also adding a MIDI thru function that echoes the incoming MIDI data on either the same port or the opposite one.

Active Sensing

This is a data byte that is sent out by some controllers every 300 milliseconds or so that lets receiving equipment know that everything is hunky dory. Mostly, it just gets in the way of whatever you might be trying to do with the MIDI data stream, so the best thing to do is just filter it out before it gets placed in the buffer. A slight change to the RxIntHand routines is all that is necessary to do this, and it consists of a grand total of two lines of assembly code.

MIDI Thru

The MIDI thru capability is pretty easy to add too. It’s another change to the RxIntHand routines that calls either TxMIDIA or TxMIDIB depending on the variable ThruFlagA or ThruFlagB. In order to set the variables two routines had to be added to the library: MIDIThruA and MIDIThruB.

The new routines

{1}
XDEF  MIDIThruA
XDEF  MIDIThruB
ThruFlagA  DC 0  ; MIDI thru flag for modem port
ThruFlagB  DC 0  ; MIDI thru flag for printer port
 
; This routine lets you do a MIDI Thru function
; The Thrucode is:
; 0 = No thru function
; 1 = MIDI thru on the same channel
; 2 = MIDI thru on the opposite channel

; Procedure MIDIThruA(Thrucode : integer);
MIDIThruA
 LEA  ThruFlagA,A0  ; point to the flag
 MOVE  4(SP),(A0)  ; set the flag
 MOVE.L  (SP)+,A0  ; save the return address
 ADDQ  #2,SP     ; move past the parameter
 MOVE.L  A0,-(SP)  ; put the return address back
 RTS      ; and return
 
; This is the interrupt routine for receiving through the
; modem port. It places the counter value and the MIDI byte in
; a circular queue to be accessed later by the application.
; When the system gets this far, A0 contains the SCC base read
; Ctl address and A1 contains the SCC base write Ctl address
; for this channel. The data addresses are offset by 4 from 
; the control addresses. D0-D3/A0-A3 are already preserved, so 
; they may be used freely.

RxIntHandA
 MOVE  SR,-(SP)  ; save status register
 ORI  #$0300,SR  ; disable interrupts
 
@3 MOVE  #4,D0   ; get data offset
 CLR.L  D1       ; prepare for data
 MOVE.L  (SP),(SP)   ; Delay
 MOVE.B  0(A0,D0),D1    ; read data from SCC
 MOVE.L  (SP),(SP)   ; Delay
 CMPI  #$FE,D1   ; filter out acitve sensing
 BEQ  @2
 LEA  ThruFlagA,A1   ; 
 CMPI  #1,(A1)   ; check for MIDI Thru
 BNE  @4
 MOVE  D1,-(SP)  ; put data on the stack
 BSR  TxMIDIA    ; send it out port A
@4

 LEA  ThruFlagA,A1   ;
 CMPI  #2,(A1)   ; check for MIDI Thru
 BNE  @5
 MOVE  D1,-(SP)  ; put data on the stack
 BSR  TxMIDIB    ; send it out port B
@5
 LEA  RxQueueA,A2  ; point to queue
 LEA  RxByteInA,A3   ; get the address
 MOVE  (A3),D0   ; get offset to next cell
 LEA  Counter,A3   ; get the address
 MOVE.L  (A3),D2   ; put counter value in D2
 LSL.L  #8,D2    ; shift counter one byte
 ADD.L  D2,D1    ; combine counter and data
 MOVE.L  D1,0(A2,D0)    ; put longword in queue
 LEA  RxQEmptyA,A3   ; get the address
 MOVE  #0,(A3)   ; reset queue empty flag
 ADDQ  #4,D0     ; update index
 CMP  #$400,D0
 BNE  @1
 MOVE  #0,D0
@1 LEA  RxByteInA,A3      ; get the address
 MOVE  D0,(A3)
 
@2 BTST.B  #0,(A0)   ; is there more data?
 BNE  @3    ; do it again if there is
 
 MOVE  (SP)+,SR  ; restore status register
 RTS      ; and return
  
; This is the interrupt routine for transmitting a byte
; through the modem port. It checks to see if there is any 
; data to send, and if there is it sends it to the SCC.  If
; there isn’t it resets the TBE interrupt in the SCC and 
; exits. When the system gets this far, A0 contains the SCC 
; base read Ctl address and A1 contains the SCC base write Ctl 
; address for this channel. The data addresses are offset by 4 
; from the control addresses. D0-D3/A0-A3 are already pre
; served, so they may be used freely.

TxIntHandA
 MOVE  SR,-(SP)  ; save the status register
 ORI  #$0300,SR  ; disable interrupts
  
 LEA  TxQEmptyA,A3   ; get the address
 TST.B  (A3)     ; Is queue empty?
 BEQ  @1    ; if not branch
 MOVE.B  #$28,(A1)   ; if so, reset TBE interrupt
 MOVE.L  (SP),(SP)   ; Delay
 BRA  TxIExitA   ; and exit
@1 LEA  TxByteOutA,A3     ; get the address
 MOVE  (A3),D0   ; get index to next data byte
 LEA  TxQueueA,A2  ; point to queue
 MOVE  #4,D1     ; get data offset
 MOVE.B  0(A2,D0),0(A1,D1)  ; write data to SCC
 MOVE.L  (SP),(SP)   ; Delay
 ADDQ  #1,D0     ; update index
 CMP  #$100,D0
 BNE  @2
 MOVE  #0,D0
@2 LEA  TxByteOutA,A3     ; get the address
 MOVE  D0,(A3)
 LEA  TxByteInA,A3   ; get the address
 MOVE  (A3),D1
 CMP  D0,D1      ; is TxQueue empty?
 BNE  TxIExitA   ; if not exit
 LEA  TxQEmptyA,A3   ; get the address
 MOVE  #$FFFF,(A3)   ; if empty set flag
 
TxIExitA
 MOVE  (SP)+,SR  ; restore status register
 RTS      ; and return

; This routine lets you do a MIDI Thru function
; The Thrucode is:
;  0 = No thru function
;  1 = MIDI thru on the same channel
;  2 = MIDI thru on the opposite channel
; Procedure MIDIThruB(Thrucode : integer);

MIDIThruB
 LEA  ThruFlagB,A0   ; point to the flag
 MOVE  4(SP),(A0)  ; set the flag
 MOVE.L  (SP)+,A0  ; save the return address
 ADDQ  #2,SP     ; move past the parameter
 MOVE.L  A0,-(SP)  ; put the return address back
 RTS      ; and return
 
; This is the interrupt routine for receiving through the
; printer port. It places the counter value and the MIDI byte
; in a circular queue to be accessed later by the appl-
; ication. When the system gets this far, A0 contains the SCC
; base read Ctl address and A1 contains the SCC base write Ctl
; address for this channel. The data addresses are offset by 4
; from the control addresses. D0-D3/A0-A3 are already pre-
; served, so they may be used freely.

RxIntHandB
 MOVE  SR,-(SP)  ; save status register
 ORI  #$0300,SR  ; disable interrupts
  
@3 MOVE  #4,D0   ; get data offset
 CLR.L  D1       ; prepare for data
 MOVE.L  (SP),(SP)   ; Delay
 MOVE.B  0(A0,D0),D1      ; read data from SCC
 MOVE.L  (SP),(SP)   ; Delay
 CMPI  #$FE,D1   ; filter out acitve sensing
 BEQ  @2
 LEA  ThruFlagB,A1
 CMPI  #1,(A1)   ; check for MIDI Thru
 BNE  @4
 MOVE  D1,-(SP)  ; put data on the stack
 BSR  TxMIDIB    ; send it out port B
@4
 LEA  ThruFlagB,A1
 CMPI  #2,(A1)   ; check for MIDI Thru
 BNE  @5
 MOVE  D1,-(SP)  ; put data on the stack
 BSR  TxMIDIA    ; send it out port A
@5
 LEA  RxQueueB,A2  ; point to queue
 LEA  RxByteInB,A3   ; get the address
 MOVE  (A3),D0   ; get offset to next cell
 LEA  Counter,A3   ; get the address
 MOVE.L  (A3),D2   ; put counter value in D2
 LSL.L  #8,D2    ; shift counter one byte
 ADD.L  D2,D1    ; combine counter and data
 MOVE.L  D1,0(A2,D0)      ; put longword in queue
 LEA  RxQEmptyB,A3   ; get the address
 MOVE  #0,(A3)   ; reset queue empty flag
 ADDQ  #4,D0     ; update index
 CMP  #$400,D0
 BNE  @1
 MOVE  #0,D0
@1 LEA  RxByteInB,A3      ; get the address
 MOVE  D0,(A3)
  
@2 BTST.B  #0,(A0)   ; is there more data?
 BNE  @3    ; do it again if there is
 
 MOVE  (SP)+,SR  ; restore status register
 RTS      ; and return
  
; This is the interrupt routine for transmitting a byte
; through the printer port.
; It checks to see if there is any data to send, and if there
; is it sends it to the SCC.  If there isn’t it resets the TBE
; interrupt in the SCC and exits. When the system gets this
; far, A0 contains the SCC base read Ctl address and A1
; contains the SCC base write Ctl address for this channel. 
; The data addresses are offset by 4 from the control addr-
; esses. D0-D3/A0-A3 are already preserved, so they may be 
; used freely.

TxIntHandB
 MOVE  SR,-(SP)  ; save status register
 ORI  #$0300,SR  ; disable interrupts
  
 LEA  TxQEmptyB,A3   ; get the address
 TST.B  (A3)     ; Is queue empty?
 BEQ  @1    ; if not branch
 MOVE.B  #$28,(A1)   ; if so, reset TBE interrupt
 MOVE.L  (SP),(SP)   ; Delay
 BRA  TxIExitB   ; and exit
@1 LEA  TxByteOutB,A3     ; get the address
 MOVE  (A3),D0   ; get index to next data byte
 LEA  TxQueueB,A2  ; point to queue
 MOVE  #4,D1     ; get data offset
 MOVE.B  0(A2,D0),0(A1,D1)  ; write data to SCC
 MOVE.L  (SP),(SP)   ; Delay
 ADDQ  #1,D0     ; update index
 CMP  #$100,D0
 BNE  @2
 MOVE  #0,D0
@2 LEA  TxByteOutB,A3     ; get the address
 MOVE  D0,(A3)
 LEA  TxByteInB,A3   ; get the address
 MOVE  (A3),D1
 CMP  D0,D1      ; is TxQueue empty?
 BNE  TxIExitB   ; if not exit
 LEA  TxQEmptyB,A3   ; get the address
 MOVE  #$FFFF,(A3)   ; if empty set flag
 
TxIExitB
 MOVE  (SP)+,SR  ; restore status register
 RTS      ; and return

The World’s dumbest MIDI program

This brings us to an actual example of how to use these routines in a typical program. For the example program I have chosen to make the Macintosh into the worlds most expensive MIDI thru box. Actually, it reminds me of when I first got my Macintosh in 1984 with just MacPaint and MacWrite available. I used to call it the $2,000 etch-a-sketch (ha ha).

At any rate, the demo program MIDI Shell lets you test out the various modes of MIDI thru by using menu selections. I also added some of my preferred techniques for writing applications in general, such as including a Transfer... menu item in the file Menu, and using an About... dialog box that doesn’t get in the user’s way.

What I mean by that last statement is that most About... boxes that I see force you to click on an OK button or something in order to continue working in the program. Now, there are some cases where you don’t have to click in the dialog box itself, but you can’t just go up and make a normal menu selection because you have to click once just to get rid of the dialog first (the finder’s About... box is an example of this way to handle it). My feeling is that the optimum way to deal with the About... dialog box is to make it possible to use the program without having to concern yourself with getting rid of the dialog box first. This is accomplished by using the scheme presented in the DoAbout procedure.

The Transfer... item in the File menu is one that I wish were in every Macintosh program. It makes life much easier by not making the user have to go back to the Finder all the time. Considering that it is so simple to implement, I end up using it in every program I write.

More ways to skin the cat

Now, I should probably point out at this time that there are other ways to deal with MIDI input and output besides the interrupt method that I have described so far. There is also a technique known as polling.

Polling is done by dropping all other considerations and just constantly looking at the receive register of the SCC chip to see if there is anything there. While it may sound really dumb at first, polling can be very useful in certain circumstances, like when you know exactly when a large amount of MIDI data is going to arrive. This happens in programs like patch librarians, for example.

Now, of course, doing polling requires an entirely different set of low level routines. Next article I’ll show you some of these routines and how to write a simple patch librarian with them. Then, in a later article, I’ll come back to the interrupt driven library to look at writing a ‘Stone Age Sequencer’. Until then, happy coding.

{2}
{ Kirk Austin, 7/12/87 }
{ This is an example program that illustrates the } 
{following techniques: }
{ My preferred method for handling the about box }
{The use of the transfer command in the file menu }
{The use of the LSPMIDI library including MIDIThru}

PROGRAM ShellExample;

 USES
 LSPMIDI;
{ Global Constants }
 CONST
 Null = ‘’;
 AppleMenuID = 1;
 FileMenuID = 2;
 EditMenuID = 3;
 MIDIMenuID = 4;
 AboutID = 200;
{ Global Variables }
 VAR
 myMenus : ARRAY[AppleMenuID..MIDIMenuID] OF MenuHandle;
 Done : Boolean; { true when user selects quit}
{This is a way to do the about box so that it doesn’t interfere with 
the application. For instance, you can make menu selections while the 
about box is visible.}

 PROCEDURE ShowAbout;
 VAR
 theDlog : DialogPtr;
 oldPort : GrafPtr;
 BEGIN
 GetPort(oldPort);
 theDlog := GetNewDialog(AboutID, NIL, Pointer(-1));
 SetPort(theDlog);
 DrawDialog(theDlog);
 WHILE NOT Button DO
 ;
 DisposDialog(theDlog);
 SetPort(oldPort);
 END;

 PROCEDURE LaunchIt (mode : integer;
 VAR fName : Str255);
 INLINE
 $204F, {movea.l  a7,a0;(a0) is string ptr, 4(a0) mode}
 $A9F2; {_Launch}


 PROCEDURE DoXfer;
 VAR
 where : Point;
 reply : SFReply;
 vRef : integer;
 thefName : Str255;
 textType : SFTypeList;
 BEGIN
 where.h := 80;
 where.v := 55;
 textType[0] := ‘APPL’;
 SFGetFile(where, Null, NIL, 1, textType, NIL, reply);
 WITH reply DO
 IF NOT good THEN
 thefName := Null
 ELSE
 BEGIN
 thefName := fName;
 vRef := vRefNum
 END;
 IF thefName <> Null THEN
 BEGIN
 Done := true;
 IF SetVol(NIL, vRef) = noErr THEN
 BEGIN
 ResetSCCA;
 ResetSCCB;
 QuitTimer;
 LaunchIt(0, thefName)
 END;
 END
 END;

 PROCEDURE ProcessMenu ( codeWord : Longint);
 { handle menu selections}
 VAR
 i : integer;
 menuNum : Integer;
 TheMenuHdle : MenuHandle;
 itemNum : Integer;
 NameHolder : str255;
 dummy : Integer;
 ignore : boolean;
 TheValue : longint;

 BEGIN
 IF codeWord <> 0 THEN  { nothing was selected}
 BEGIN
 menuNum := HiWord(codeWord);
 itemNum := LoWord(codeWord);
 CASE menuNum OF { the different menus}
 AppleMenuID : 
 BEGIN
 IF itemNum < 3 THEN
 BEGIN
 ShowAbout;
 END
 ELSE
 BEGIN
 GetItem(myMenus[AppleMenuID], itemNum, NameHolder);
 dummy := OpenDeskAcc(NameHolder);
 END;
 END;
 FileMenuID : 
 BEGIN
 CASE ItemNum OF
 1 : 
 BEGIN
 DoXfer;
 END;
 2 : 
 BEGIN
 Done := true;
 END;
 END;
 END;
 EditMenuID : 
 BEGIN
 ignore := SystemEdit(itemNum - 1);
 END;
 MIDIMenuID : 
 BEGIN
 TheMenuHdle := GetMHandle(4);
 FOR i := 1 TO 5 DO
 CheckItem(TheMenuHdle, i, false);
 MIDIThruA(0);
 MIDIThruB(0);
 CASE ItemNum OF
 1 : 
 BEGIN
 CheckItem(TheMenuHdle, 1, true);
 MIDIThruA(1);
 END;
 2 : 
 BEGIN
 CheckItem(TheMenuHdle, 2, true);
 MIDIThruA(2);
 END;
 3 : 
 BEGIN
 CheckItem(TheMenuHdle, 3, true);
 MIDIThruB(1);
 END;
 4 : 
 BEGIN
 CheckItem(TheMenuHdle, 4, true);
 MIDIThruB(2);
 END;
 5 : 
 BEGIN
 CheckItem(TheMenuHdle, 5, true);
 MIDIThruA(0);
 MIDIThruB(0);
 END;
 END;
 END;
 END;
 HiliteMenu(0);
 END;
 END;

 PROCEDURE DealWithMouseDowns (theEvent : EventRecord);
 VAR
 location : Integer;
 windowPointedTo : WindowPtr;
 mouseLoc : point;
 windowLoc : integer;
 VandH : Longint;
 Height : Integer;
 Width : Integer;
 BEGIN
 mouseLoc := theEvent.where;
 windowLoc := FindWindow(mouseLoc, windowPointedTo);
 CASE windowLoc OF
 inMenuBar : 
 BEGIN
 ProcessMenu(MenuSelect(mouseLoc));
 END;
 inSysWindow : 
 BEGIN
 SystemClick(theEvent, windowPointedTo);
 END;
 OTHERWISE
 BEGIN
 END;
 END;
 END;

 PROCEDURE DealWithKeyDowns (theEvent : EventRecord);
 TYPE
 Trick = PACKED RECORD
 CASE boolean OF
 true : (
 long : Longint
 );
 false : (
 chr3, chr2, chr1, chr0 : char
 )
 END;
 VAR
 CharCode : char;
 TrickVar : Trick;
 BEGIN
 TrickVar.long := theEvent.message;
 CharCode := TrickVar.chr0;
 IF BitAnd(theEvent.modifiers, CmdKey) = CmdKey THEN 
 {check for a menu selection}
 BEGIN
 ProcessMenu(MenuKey(CharCode));
 END
 END;

 PROCEDURE MainEventLoop;
 VAR
 Event : EventRecord;
 ProcessIt : boolean;
 x : byte;
 TheValue : Longint;
 BEGIN
 REPEAT
 SystemTask;
 ProcessIt := GetNextEvent(everyEvent, Event); 
 { get the next event in queue}
 IF ProcessIt THEN
 BEGIN
 CASE Event.what OF
 mouseDown : 
 DealWithMouseDowns(Event);
 AutoKey : 
 DealWithKeyDowns(Event);
 KeyDown : 
 DealWithKeyDowns(Event);
 OTHERWISE
 BEGIN
 END;
 END;
 END;
 UNTIL Done;
 END;

 PROCEDURE MakeMenus;{ get the menus & display them}
 VAR
 index : Integer;
 TheMenuHdle : MenuHandle;
 BEGIN
 FOR index := AppleMenuID TO MIDIMenuID DO
 BEGIN
 myMenus[index] := GetMenu(index);
 InsertMenu(myMenus[index], 0);
 END;
 AddResMenu(myMenus[AppleMenuID], ‘DRVR’);
 DrawMenuBar;
 {put a check mark on the “none” menu item by default}
 TheMenuHdle := GetMHandle(4);
 CheckItem(TheMenuHdle, 5, true);
 END;

{ Program Starts Here }
BEGIN
 Done := false;
 FlushEvents(everyEvent, 0);

 InitSCCA;
 InitSCCB;
 InitTimer(782 * 5); 
 {increment the counter every 5 milliseconds}
 StartCounter;

 MakeMenus;
 InitCursor;
 MainEventLoop;

 ResetSCCA;
 ResetSCCB;
 QuitTimer;

END.


UNIT LSPMIDI;
{Midi library available on this source code disk for LSP }
INTERFACE
 PROCEDURE InitSCCA;
 {call this once at the beginning of your application if you are going 
to use the modem port for MIDI}

 PROCEDURE TxMIDIA (TheData : integer);
 {use this procedure to transmit a byte of MIDI data through the modem 
port the MIDI byte is in the lower 8 bits of the word}

 FUNCTION RxMIDIA : LongInt;
 {use this function to get a byte of MIDI data and the counter value 
associated with that byte through the modem port the MIDI byte is in 
the lower 8 bits of the longword the upper 3 bytes of the longword contain 
the counter value when the byte arrived at the Macintosh}

 PROCEDURE MIDIThruA (Thrucode : integer);
 {this is for the MIDI thru function}
 {the Thrucode variable is as follows:}
 {0 = no MIDIThru function}
 {1 = MIDIThru on the same channel}
 {2 = MIDIThru on the opposite channel}

 PROCEDURE ResetSCCA;
 {call this procedure when your application is done if you called InitSCCA 
at the beginning of your application or the system will crash}

 PROCEDURE InitSCCB;
 {call this once at the beginning of your application if you are going 
to use the printer port for MIDI}

 PROCEDURE TxMIDIB (TheData : integer);
 {use this procedure to transmit a byte of MIDI data through the printer 
port the MIDI byte is in the lower 8 bits of the word}

 FUNCTION RxMIDIB : LongInt;
 {use this function to get a byte of MIDI data and the counter value 
associated with that byte through the printer port the MIDI byte is in 
the lower 8 bits of the longword the upper 3 bytes of the longword contain 
the counter value when the byte arrived at the Macintosh}

 PROCEDURE MIDIThruB (Thrucode : integer);
 {this is for the MIDI thru function}
 {the Thrucode variable is as follows:}
 {0 = no MIDIThru function}
 {1 = MIDIThru on the same channel}
 {2 = MIDIThru on the opposite channel}

 PROCEDURE ResetSCCB;
 {call this procedure when your application is done if you called InitSCCB 
at the beginning of your application or the system will crash}

 PROCEDURE InitTimer (TimrValue : integer);
 {call this procedure once at the beginning of your application if you 
are going to make use of time-stamping.  1 millisecond = decimal 782}

 PROCEDURE LoadTimer (TimrValue : integer);
 {call this procedure if you want to change the interval of time that 
the counter is incremented.  1 millisecond = decimal 782}

 PROCEDURE StartCounter;
 {call this procedure to set the counter value to 1}

 FUNCTION GetCounter : LongInt;
 {call this function to get the current value of the counter}

 PROCEDURE QuitTimer;
 {call this procedure when your application is done if you called InitTimer 
at the beginning of your application or the system will crash}

IMPLEMENTATION
{$A+}
 PROCEDURE InitSCCA;
 external;
 PROCEDURE TxMIDIA;
 external;
 FUNCTION RxMIDIA;
 external;
 PROCEDURE MIDIThruA;
 external;
 PROCEDURE ResetSCCA;
 external;
 PROCEDURE InitSCCB;
 external;
 PROCEDURE TxMIDIB;
 external;
 FUNCTION RxMIDIB;
 external;
 PROCEDURE MIDIThruB;
 external;
 PROCEDURE ResetSCCB;
 external;
 PROCEDURE InitTimer;
 external;
 PROCEDURE LoadTimer;
 external;
 PROCEDURE StartCounter;
 external;
 FUNCTION GetCounter;
 external;
 PROCEDURE QuitTimer;
 external;
{$A-}

END.
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Alfred 3.2.1 - Quick launcher for apps a...
Alfred is an award-winning productivity application for OS X. Alfred saves you time when you search for files online or on your Mac. Be more productive with hotkeys, keywords, and file actions at... Read more
OmniPlan 3.6 - Robust project management...
With OmniPlan, you can create logical, manageable project plans with Gantt charts, schedules, summaries, milestones, and critical paths. Break down the tasks needed to make your project a success,... Read more
Backblaze 4.2.0.990 - Online backup serv...
Backblaze is an online backup service designed from the ground-up for the Mac. With unlimited storage available for $5 per month, as well as a free 15-day trial, peace of mind is within reach with... Read more
AppDelete 4.3.1 - $7.99
AppDelete is an uninstaller that will remove not only applications but also widgets, preference panes, plugins, and screensavers along with their associated files. Without AppDelete these associated... Read more
Apple GarageBand 10.1.4 - Complete recor...
The new GarageBand is a whole music creation studio right inside your Mac -- complete with keyboard, synths, orchestral and percussion instruments, presets for guitar and voice, an entirely... Read more
Adobe Lightroom 6.8 - Import, develop, a...
Adobe Lightroom is available as part of Adobe Creative Cloud for as little as $9.99/month bundled with Photoshop CC as part of the photography package. Lightroom 6 is also available for purchase as a... Read more
iMazing 2.1.3 - Complete iOS device mana...
iMazing (was DiskAid) is the ultimate iOS device manager with capabilities far beyond what iTunes offers. With iMazing and your iOS device (iPhone, iPad, or iPod), you can: Copy music to and from... Read more
Little Snitch 3.7.1 - Alerts you about o...
Little Snitch gives you control over your private outgoing data. Track background activity As soon as your computer connects to the Internet, applications often have permission to send any... Read more
OmniPlan Pro 3.6 - Professional-grade pr...
With OmniPlan Pro, you can create logical, manageable project plans with Gantt charts, schedules, summaries, milestones, and critical paths. Break down the tasks needed to make your project a success... Read more
Apple GarageBand 10.1.4 - Complete recor...
The new GarageBand is a whole music creation studio right inside your Mac -- complete with keyboard, synths, orchestral and percussion instruments, presets for guitar and voice, an entirely... Read more

Latest Forum Discussions

See All

Galaxy on Fire 3 and four other fantasti...
Galaxy on Fire 3 - Manticore brings the series back for another round of daring space battles. It's familiar territory for folks who are familiar with the franchise. If you've beaten the game and are looking to broaden your horizons, might we... | Read more »
The best apps for your holiday gift exch...
What's that, you say? You still haven't started your holiday shopping? Don't beat yourself up over it -- a lot of people have been putting it off, too. It's become easier and easier to procrastinate gift shopping thanks to a number of apps that... | Read more »
Toca Hair Salon 3 (Education)
Toca Hair Salon 3 1.0 Device: iOS Universal Category: Education Price: $2.99, Version: 1.0 (iTunes) Description: | Read more »
Winter comes to Darkwood as Seekers Note...
MyTona, based in the chilly Siberian city of Yakutsk, has brought a little festive fun to its hidden object game Seekers Notes: Hidden Mystery. The Christmas update introduces some new inhabitants to players, and with them a chance to win plenty of... | Read more »
Bully: Anniversary Edition (Games)
Bully: Anniversary Edition 1.03.1 Device: iOS Universal Category: Games Price: $6.99, Version: 1.03.1 (iTunes) Description: *** PLEASE NOTE: This game is officially supported on the following devices: iPhone 5 and newer, iPod Touch... | Read more »
PINE GROVE (Games)
PINE GROVE 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: A pine grove where there are no footsteps of people due to continuous missing cases. The case is still unsolved and nothing has... | Read more »
Niantic teases new Pokémon announcement...
After rumors started swirling yesterday, it turns out there is an official Pokémon GO update on its way. We’ll find out what’s in store for us and our growing Pokémon collections tomorrow during the Starbucks event, but Niantic will be revealing... | Read more »
3 reasons why Nicki Minaj: The Empire is...
Nicki Minaj is as business-savvy as she is musically talented and she’s proved that by launching her own game. Designed by Glu, purveyors of other fine celebrity games like cult favorite Kim Kardashian: Hollywood, Nicki Minaj: The Empire launched... | Read more »
Clash of Clans is getting its own animat...
Riding on its unending wave of fame and success, Clash of Clans is getting an animated web series based on its Clash-A-Rama animated shorts.As opposed to the current shorts' 60 second run time, the new and improved Clash-A-Rama will be comprised of... | Read more »
Leaks hint at Pokémon GO and Starbucks C...
Leaked images from a hub for Starbucks employees suggests that a big Pokémon GO event with the coffee giant could begin this very week. The images appeared on Reddit and hint at some exciting new things to come for Niantic's smash hit game. | Read more »

Price Scanner via MacPrices.net

12-inch Retina MacBooks, Apple refurbished, n...
Apple has restocked a full line of Certified Refurbished 2016 12″ Retina MacBooks, now available for $200-$260 off MSRP. Refurbished 2015 models are available starting at $929. Apple will include a... Read more
Holiday sale: 12-inch Retina MacBook for $100...
B&H has 12″ Retina MacBooks on sale for $100 off MSRP as part of their Holiday sale. Shipping is free, and B&H charges NY sales tax only: - 12″ 1.1GHz Space Gray Retina MacBook: $1199 $100... Read more
Apple refurbished 13-inch MacBook Airs availa...
Apple has Certified Refurbished 13″ MacBook Airs available starting at $849. An Apple one-year warranty is included with each MacBook, and shipping is free: - 13″ 1.6GHz/8GB/128GB MacBook Air: $849 $... Read more
Apple refurbished iMacs available for up to $...
Apple has Certified Refurbished 2015 21″ & 27″ iMacs available for up to $350 off MSRP. Apple’s one-year warranty is standard, and shipping is free. The following models are available: - 21″ 3.... Read more
Apple’s Education discount saves up to $300 o...
Purchase a new Mac or iPad using Apple’s Education Store and take up to $300 off MSRP. All teachers, students, and staff of any educational institution qualify for the discount. Shipping is free: -... Read more
Back in stock: Apple refurbished Mac minis fr...
Apple has Certified Refurbished Mac minis available starting at $419. Apple’s one-year warranty is included with each mini, and shipping is free: - 1.4GHz Mac mini: $419 $80 off MSRP - 2.6GHz Mac... Read more
Twenty-Five Years Of Apple Laptops – A person...
Among many other things, the often tumultuous 16th year of the new century marked the 25th anniversary of Apple laptop computers, not counting the optimistically named 16-pound Mac Portable of 1989.... Read more
Landlordy iOS App Adds Support For Appliances...
Riga, Latvia based E-protect SIA is releasing major update (version 1.8) to its Landlordy app for managing rental business financials on the go. Landlordy is iPhone and iPad app designed for self-... Read more
Holiday sale, Apple iMacs for up to $200 off...
B&H Photo has 21″ and 27″ Apple iMacs on sale for up to $200 off MSRP including free shipping plus NY sales tax only: - 27″ 3.3GHz iMac 5K: $2099 $200 off MSRP - 27″ 3.2GHz/1TB Fusion iMac 5K: $... Read more
Holiday sale: Mac minis for $50 to $100 off M...
B&H Photo has Mac minis on sale for up to $100 off MSRP free shipping plus NY sales tax only: - 1.4GHz Mac mini: $449 $50 off MSRP - 2.6GHz Mac mini: $629 $70 off MSRP - 2.8GHz Mac mini: $899 $... Read more

Jobs Board

*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions- Trumbul...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Retail - Multiple Positions- Philade...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions- San Ant...
Job Description:SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Products Tester Needed - Apple (Unit...
…we therefore look forward to put out products to quality test for durability. Apple leads the digital music revolution with its iPods and iTunes online store, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.