amiga world tech journal vol 01-01-1991 apr may
DESCRIPTION
Control Audio Hardware, Sprites, IFF Standard, AmigaDOS Device List, Shared Libraries, Fast File System.TRANSCRIPT
Captain's log 2i 7;2055
Time shift equalization routines recoded in
Aztec C. All systems go. It's good to be back home.
Call Today for
Special Discount Prices
and Technical Information
Space Suiton 2055 - I lido Potiharpus
- -r
Aztec C is available for Amiga, Macintosh, MS-DOS, Apple II,
TRS-80, and CPM/80. Native and cross development.
Aztec Embedded C hosts on MS-DOS and Macintosh. Targets
include: 68000 family. 8086 family, 8080/Z80/64180, & 6502
Aztec C includes ■ C compiler, assembler, linker, librarian,
editor, source debugger, and other development tools.
MANX08OO-221-O44O• Outside USA: 908-542-2121 FAX: 908-542-8386 • Visa, MC, Am Ex, C.O.D,
domestic & international wire • one and two day delivery available
Manx Software Systems • 160 Avenue of the Commons • Box 55 • Shrewsbury NJ 07702
" MESSAGE PORTFinally, The First
AT LAST. The AmigaWorld Tech Jour
nal's premiere issue is done and in
your hands. Since 1987 when the idea
for a technical journal was first pro
posed, I've feared it would forever be
buried in the "Good Ideas That We
Ought To Get Back To Someday" pile.
More persistent than most, the tech
journal proposal kept bubbling its
way to the top of the stack. Each stint
at the top refined the idea a bit more.
By last fall, the once hard-core, profes-
sional-developers-only newsletter had
expanded into a magazine for all tech
nically inquisitive and serious Amiga
users. The two most exciting and im
portant enhancements were the
founding of the Peer Review Board
and the addition of a companion disk.
Staffed by engineers and profes
sional programmers, the Peer Review
Board is dedicated to ensuring the ac
curacy of all articles and keeping The
Journal's technical level high. Graphics
specialists read the "Graphics Han
dler" column, the operating system
developers read "Digging Deep in the
OS," Commodore hardware designers
and CATS members make sure the
system specs we print are the system
specs they created. Peer Reviewers
check the text and test all associated
code thoroughly, primarily concen
trating on the facts, but also consider
ing the article's solution to the
presented problem, We want to teach
good programming practices, not just
provide keen routines. If a listing's ap
proach is a too roundabout, we'll
make the author untangle the snarl of
gotos, reconsider, and rewrite.
To minimize "Yes, it's perfectly fine,
but my code's better" arguments, each
article is read by two reviewers. This
way, when code wars do arise, the
four-way discussion usually results in
new article ideas and more information
for the reader, instead of a standoff.
(If you're saying "I could do that. I
know as much as these guys, probably
more!" maybe you should be giving
me a call.)
While the Peer Review Board im
proves The journal's quality, the inclu
sion of a disk with every issue
expands its range. No longer do we
have to turn down valuable articles
because the code would fill three-
quarters of our pages. Instead, I just
copy the source and executable files to
a disk, and hand it to Mare-Anne Jar-
vela, our manager of disk products
and jigsaw-puzzle whiz, who com
piles the disk you'll find on page 25.
Any leftover space she quickly rills
with utilities and PD languages. Best
of all, you don't have to retype the
routines you need only to spend
hours and hours hunting for that lost
semicolon. Hurray!
BUT WHAT WILL WE READ
ABOUT?
While we aim to help you become a
better programmer and more techni
cally aware, we're not going to waste
your time with three-part disserta
tions on C's printf( ) command or
how to hook up your VCR. We will
teach you how to better use the Ami
ga's unique capabilities—which ROM
Kernel routines to call when, how the
hardware works, which graphics algo-
rithmns to use, and so on. By covering
all the major languages, we'll help
you make the jump from BASIC to C,
or C to assembly, or tie everything to
gether with ARexx.
I can't promise Technicolor, Cine
mascope, surround sound, or the fa
mous "Cast Of Thousands," but here
are a few of The AmigaWorld Tech jour
nal's coming attractions:
• Using CreatePortf) and Delete-
Port( ) to write an input handler.
• 3-D graphics algorithms and
implementations
• Handling HAM
• C compilers: SAS versus Manx
• A roundup of time-base correctors
• A thorough examination of the
NTSC/RS170A standard
• Controlling/monitoring IPC (inter
process communications)
• Writing an Anim player
• Inside ARexx, ARexx and the
Toaster, ARexx and you name it
• An explanation of the MIDI
standard
• Taking advantage of Super Denise's
new genlock modes
• Programming Unix
• Working with object-oriented
programming and C + +
• Understanding outline font
technology
Waiting for a topic that you don't
see? Let's hear from you then! I'm al
ways open to your suggestions.
During the the Amiga's dark ages
when few people had even heard of
the machine, let alone used one, the
techies loyally stood behind it, educat
ing anyone who would listen. Now
the bandwagon is finally filling up
with neophytes boasting "I always
knew the machine would just take off
one day," you can smile and say, "Ah,
but I worked with her when. . ." The
AmigaWorld Tech Journal is here to rec
ognize that dedication and foster your
new innovations, a professional publi
cation for a professional machine.
At last.
The AW Tech journal 1
Linda Barrett Laflamme, Editor
Louis R. Wallace, Technical Advisor
Barbara Gefvert, Beth Jala, Peg LeFage, Copy Editors
Brad Carvey
Joanne Dow
Keith Doyle
Andy Finkel
John Foust
Jim Goodnow
Scott Hood
David Joiner
Sheldon Leemon
Dale Luck
R.J. Mical
Eugene Mortimore
Bryce Nesbitt
Carolyn Scheppner
Leo Schwab
Steve Tibbett
John Toebes
Peer Review Board
Mare-Anne Jarvela, Manager, Disk Projects
Laura Johnson, Designer
Alana Korda, Production Supervisor
Debra A. Davies, Typographer
Kenneth Blakeman, National Advertising Sales Manager
Barbara Hoy, Sales Representative/Northeast
Michael McGoldrick, Sales Representative/
Midwest, Southeast
Heather Guinard, Sales Representative/Partial Pages,
800/441-4403, 603/924-0100
Meredith Bickiord, Advertising Coordinator
Giorgio Saluti, Associate Publisher, West Coast Sales,
415/363-5230
2421 Broadway, Suite 200, Redwood City, CA 94063
Wendie Haines Marro, Marketing Director
Laura Livingston, Marketing Coordinator
Margot L. Swanson, Customer Service Representative,
Advertising Assistant
Lisa LaFleur, Business and Operations Administrator
Mary McCole, Publisher's Assistant
Susan M. Hanshaw, Circulation Director, 800/365-1364
Pam Wilder, Circulation Manager
Lynn Lagasse, Manufacturing Manager
Roger J. Murphy, President
Bonnie Welsh-Carroll, Director of Corporate
Circulation & Planning
Linda Ruth, Single Copy Sales Director
Debbie Walsh, Newsstand Promotion Manager
William M. Boyer, Director of Credit Sales & Collections
Stephen C. Robbins, Vice-President/Group Publisher
Douglas Barney, Editorial Director
TlieAmigaWarld Tech Journal (ISSN 1054-4631) is an independent journal not connected with Commodore Business Machines
Inc. The AmigaWarld Tech Journal is published bimonthly by IDC CommunicatioiutfFeteiborough. Inc., 80 Elm St., Peterbor
ough, NH 03458. U.S. Subscription rate is $69.95, Canada and Mexico 579.95, Foreign Surface 589,95, Foreign Airmail 5109.95.
All prices are for one year. Prepayment is required in U.S. funds drawn on a U.S. bank. Application to mail at 2nd class
postage rates is pending at Peterborough, NH and additional mailing offices- Phone: 603/924-0100. Entire contents copyright
1991 by IDG Communications/Peterborough, Inc. No part of this publication may be printed or otherwise reproduced
without written permission from the publisher. Postmasler Send address changes to The AmigaWarld Tech journal, 80 Elm
St., Peterborough, NH 03458. The AmigaVforld Tech Journal makes every effort to assure the accuracy of articles, listings, and
circuits published in the magazine. The Ami^aWttrld Tech Journal assumes no responsibility for damages due to errors or
omissions. Third class mail enclosed.
Bulk Raft?
US Postage Paid
IDG Communications/Peterborough, Inc.
2 April/May 1991
" A source of technicalinformation for the serious
Amiga professional.Introducing The AmigaWorld Itch Journal,
the new source to turn to for the advanced
technical information you crave.
Whether you're a programmer or a
developer of software or hardware,you simply can't find a more useful
publication than this. Each big, bi
monthly issue is packed with fresh,
authoritative strategies and advice
to help you fuel the power of your
computing.
Trying to get better results from
yj2U^BASIC compiler? Looking for
Public Domain programming
on the networks and bulletinboards? Like to keep current on
Commodore's new standards? Wantto dig deeper into your operating
system and even write your own
lioraries? Then The AmigaWorld TechJournal is for you!
Our authors are programmers themselves, seasoned professionals who rank among the Amiga
community's foremost experts. You'll benefitfrom their knowledge and insight on C, BASIC,
Assembly, Modula-2, ARexx and the operating
system—in addition to advanced video, MIDI,speech and lots more.
Sure, other programming publications may include some technical information, but none
devote every single page to heavyweight techniques, hard-core tutorials, invaluable reviews,listings and utilities as we do.
Every issue includes
a valuable companion disk!
And only The AmigaWorld Tech Journal boasts
of a technical advisory board comprised of industry peers. Indeed, our articles undergo ascrupulous editing and screening process. So you
can rest assured our contents are not onlyaccurate, but completely up-to-date as well.
Plus! Each issue comes with a valuable companion disk, including executable code, source code
The AmigaWorld
TECH JOURNAL
and the required libraries for all our program
examples-plus the recommended PD utilities,
demos of new commercial tools and other helpful
surprises. These disks will save you the time,money and hassle of downloading PD utilities,
typing in exhaustive listings, tracking down errors
or making phone calls to on-line networks.
In every issue of The AmigaWorld Tech Journal,you'll find...• Practical hardware and software reviews, in
cluding detailed comparisons, benchmark
results and specs
• Step-by-step, high-end tutorials on such topicsas porting your work to 2.0, debugging, using
SMPTE time code, etc.
• The latest in graphics programming, featuring
algorithms and techniques for texture mapping,hidden-line removal and more
• TNT (tips, news and tools), a column covering
commercial software, books and talk on (he
networks
• Programming utilities from PD disks, bulletin
board systems and networks
• Wise buys in new products-from language
system upgrades to accelerator boards to editing systems and more.
The fact is, there's no other publication like The
AmigaWorld Tech Journal available. It's all the
tips and techniques you need. All in one single
source. So subscribe now and get the most out of
your Amiga programming. Get six fact-filled
issues. And six jam-packed disks. All at special
Charter savings. Call 1-800-343-0728 or complete
and return the savings form below—today!
To order, use
this handy
orm.
Charter Savings Forma Vacl KriteriTiy onf:Tear (6issiies-/''^ 6 invaluable
ICb! disks) Charter Subscription to The AmigaWbrldTech Journal fur just $59.95. That's a special savings of S29.75 offthe single-copy price. If a! any time I'm no! satisfied with The
AmigaWorld Tech Journal, I'm entitled lo receive a fail refund-
no questions asked!
Name _
Address
City State. Zip
D Check or money order enclosed. [ J Charge my:} MasterCard J Visa □ Discover □ American Express
Account No. Exp. Date
Signature .
Satisfaction
Guaranteed!Or your money back!
Canada and Mexico. S74.95.
Foreign surface, $84.97.Foreign airmail, S99.95.
Payment required in U.S.
funds drawn on U.S. bank.
Complete and mail to:
TheAmigaWorld
TechjoumalP.O. Box 802,80 Elm Street
Peterborough, NH 03458
T491
For faster
service, call
toll-free
1-800-343-0728.
Menus For
A New GenerationBy David "Talin" Joiner
A POLISHED INTERFACE can make or break a program's
success. Remember, users may spend all day long looking at
a single program, and they are liable to shy away from an
application with hard to read or cryptic menus, no matter
how many functions it has. When properly implemented,
menus can be visually pleasing and intuitively organized,
and should adapt to the user's customized environment.
While what constitutes "visually pleasing" is a matter of
taste, outlining how to ensure that menus conform to user-
specified options is easy.
GIVE THEM AN OPTION AND
THEY'LL TAKE A MENU
One of the biggest changes in Amiga OS 2.0 is that the user
gained much more control over system appearance. For ex
ample, in 1.3 and earlier, to get a CLI to use a font other than
Topaz requires a substantial bit of hackery. Under 2.0, how
ever, changing the font requires only a few mouse clicks
in a Preferences editor. Two of the most obvious attributes
that affect the appearance of menus are fonts and screen
colors.
Fonts: Menu appearance is determined greatly by the
text's size and typeface. Many applications have a hard-
coded font and hard-coded menus. Numerous others use the
default font, but foolishly assume that it will always be Topaz
8. The result is an unreadable mess. Smart applications use
the system's default font (which the user can change) and
adjust their menus accordingly.
When a program draws a menu item, it first checks in the
font pointer of the IntuiText item attached to the menu. If
the font pointer is NULL, then the program looks in the
screen structure for the screen font. (Note that the menu
headers on the menu bar always use this pointer, because
they have no place to put a font pointer.) The screen's font
pointer is set when the screen is first opened. If the screen
has not been informed what font it should use, it defaults to
the global ScreenFont pointer. In 2.0, the user can set the
screen font via the Fonts Preferences editor.
For many applications all you need to do is make sure that
the screen font pointer is set to a known font and then hard-
code the menu item positions based on that font's size. I
strongly recommend, however, that you go the extra dis
tance and use the system screen font, adjusting the menu
items to fit. The reason is simple: With some of the new high-
resolution graphics modes (or a visually-impaired user),
those small fonts may be completely unreadable.
Colors: Because the default palette is different under 2.0,
menus appear dark instead of white (for the reasons behind
4 April/Mai/1991
this, see the "Digging Deep in the OS" column). I do not
advise trying to change this color scheme, because the Amiga
A symbol is a hard-coded image in the Kickstart ROM and
cannot be changed. If the window's BlockPen is set to any
thing other than 1, the character will look ghastly. (This is
also true under 1.3.)
Another consideration is that some users are going to be
in monochrome mode. Because the new Productivity mode
takes up a lot of system bandwidth, users who want the extra
resolution but not the speed penalty may drop down to a
single bitplane. To be safe, make sure that all your menus are
easy to read on a two-color screen. The new Drawinjo struc
ture can be a help here; it has an array of pen colors that you
can use as advice when drawing such things as dropsha-
dows, text, and so on.
Applications that open their own custom screen are not s—S
quite so constrained; they do not have to keep the colors in
the same order as the Workbench screen. The Drawlnfo
structure allows remapping of all the pens used by the sys
tem imagery.
To further help you conform your menus (and more) to
the new look of Amiga OS 2.0 Commodore is working on an
extensive set of user interface design standards, which is
scheduled to be published in the spring. This comprehensive
document will help application writers design their pro
grams to share a common look and feel with other popular
Amiga programs, making all of them more familiar and easier
to learn.
ELEMENTAL CONCERNS
With the broader changes clarified, let's make a closer in
spection of a menu's individual features and see what you
must do to make them functional and attractive.
Text Items: Include some white space around the text. I
usually make the menu highlight area three to four pixels
taller than the actual font and center the text in the highlight
area. Normally, I do not take the area below the font baseline
into account when centering, but that's just my personal
preference. As long as all the highlight boxes are the same
width they should look fine. Make the highlight areas wide
enough to just touch one another, but not overlap. This is
especially important for submenus; if the highlights overlap
annoying flashing will result.
Images: Only a very few programs benefit from using >—'
images rather than text in menu items, usually for such op
tions as line width or line pattern selection. I recommend that
you avoid using images to represent commands in menus;
menus that use images tend to be incomprehensible.
~
Attention to user-defined details
and use of the GadTools library will ensure that your menus are
functional and attractive under 2.0.
Command-key Symbol: This symbol appears whenever
a menu item has a keyboard equivalent. Unlike the check
mark, the command-key symbol cannot be changed. It
is always blitted in as a rectangle with no masking, and
the four corner pips are rendered in Pen 1. For visual
continuity, therefore, the menu box background must be
rendered in Pen 1, which is controlled by the BlockPen of
the window.
Requester Indicator: According to the Amiga user-inter
face standards (both the old ones in the Amiga ROM Kernel
Reference Manual: Libraries and Devices [Addison-Wesley] and
the new ones), any time a menu item represents a feature
that would cause a temporary interruption in the flow of in
put (such as displaying a file requester) the text for that menu
nitemshould end with an ellipsis (...)■ This is a standard clue
that the user will be presented with more choices and will
have to do additional clicking and selecting to return to the
original location.
Submenu Indicator: A second standardized clue, the
submenu indicator is the Alt-0 character, which looks like
two tiny greater-than symbols (>) pressed together. When
ever one of your menus has submenus, put a submenu in
dicator on the right edge of the menu highlight box. If the
menus are in a proportional font, adusting the spacing so
that the symbol appears exactly at the right edge may
be difficult.
You can get around this by linking to the first IntuiText
structure a second one that contains only the Alt-0 character.
You can then adjust the symbol's position down to a pixel.
An added advantage of this method is that all the items
within the same menu heading can use that second IntuiText
structure, because the spacing relative to the menu highlight
box will be exactly the same for each item.
Accelerator Keys: These are command keys that do not
require the user to press the Amiga key. (Electronic Arts'
DeluxePaint III, for example, has many of these.) Accelerator
keys usually appear in the menu on the right side of the high
light box. Sometimes a modifier key will also be listed, as in
Alt-A. The right justification techniques for the submenu in
dicator apply here as well.
Separator Bar: A new feature is the separator bar, a line
of dots that separates the menu items into logical groups,
r—-s (You can see one in the Icons menu of Workbench 2.0.) The
separator bar is an actual menu item, although it is disabled
so that it will not highlight. The imagery for the standard
separator bar is really a two-pixel-thick horizontal solid line
that has then been ghosted because the menu is disabled.
You can fake one of these easily using an image and can ar
range it so that you need only one such image per menu
header.
ALL IN THE ROUTINE
Having an application individually adjust the position of
each menu, menu item, and associated symbols would be far
too tedious and inefficient. The solution is to create an auto
matic menu layout routine. First you create a set of structures
describing the desired menus (these structures may or may
not be actual Intuition Menu structures), then lay out rou
tines that use these structures to build a linked list of menu
structures to attach to the window. This works well in prac
tice, as long as you are willing to make certain assumptions.
Most applications use less than one third of the possible fea
tures that menus provide, so you can greatly simplify the
design of the layout routines by assuming that the menus
will be relatively homogenous.
Amiga OS 2.0 has a set of layout subroutines ready-made
as part of the GadTools shared library. This system works
splendidly, but only under 2.0. If your application needs to
work under both 1.3 and 2.0, it will require a its own layout
routines. Fortunately, designing them is not hard; I suggest
using GadTools as a model.
The problem of writing a layout engine can be divided into
two parts: creating the menus and laying out the menus. The
reason for dividing it this way is that some applications have
menus that change based on the mode they are in. You do
not want to re-create all the menus every time the mode
switches happens; you just want to reposition them to ac
commodate the changes. If the program is a quickie, you can
do away with the creation part altogether and supply ready-
made menu items that are modified by the layout phase. This
may be tedious, however, if the menu has a lot of subitems
and accelerator keys.
The creation phase is fairly simple. Allocate a Menultem
structure for each text item or separator bar, plus an IntuiText
(and associated text buffer) for each text label, accelerator key,
and subitem symbol. Apply some cleverness, and you will
need to create only one subitem symbol for each menu header.
The program must also keep track of these items so that it can
deallocate them on exit. One way to do this is to walk the list
of menu items, freeing any structures encountered.
The laying out procedure is somewhat more complex, but
still fairly straightforward. The first thing the program must
do is gain access to the screen structure. If the window is al
ready open, then your program can just look in the Window-
>WScreen pointer. If the application is using a custom screen
with a hard-coded font, then it can just use that. On the other ■
The AW Tech journal 5
Menus for a New Generation
hand, if the window is going to open on the Workbench screen
or on a custom screen that shares the same attributes as the
Workbench screen, then your program must gain access to the
Workbench screen. Under 1.3, GetScreenData( ) should be
used, while under 2.0 LockPubScreen( ) is preferred. Write the
code so as to choose between these two methods based on the
version of the operating system.
Once a Screen structure (either Workbench or Custom) has
been snagged, you can figure out which font to use and the
screen's size and depth. This information is passed to the lay
out routine so that it knows how large the text items are.
Next, you must lay out the menu headers. If you do not
have enough room on the screen to lay out all the headers,
the routine might choose to either drop items or abort en
tirely, returning a failure result.
Now, the layout routine goes through each menu. On the
first pass, it calculates how big each item has to be to hold all
its elements (the text label, the command-key symbols, sub
menu symbols, and so on) and keeps track of the size of the
largest item. On the second pass, it makes all the items the
same size as the largest and sets their vertical spacing based
on whether the item is a text item or a separator bar. Also, if
the menu header is near the right edge of the screen, the
items will need to be offset to the left so that they do not run
off the right screen edge.
You must also check that the menu does not have so many
items (or use so large a font) that the list extends below the
bottom of the screen. This not only looks bad, it can cause
Intuition to crash with gorgeous fireworks. The solution is to
drop down to a smaller font and start the layout all over
again or to make multiple columns of text menu items.
GadTools uses the latter strategy. (In case you were won
dering, Intuition supports a maximum of 31 menus with 63
items per menu and 31 subitems per item.)
After the program positions the highlight boxes, it must
place the text items in the boxes. Text and symbols should be
centered vertically. Text items should be left-justified, while
symbols arc right-justified. (Ignore command keys at this
stage; they are provided by Intuition.) Now all you need to do
is attach the menu strip to the window and start collecting
events. (For an example of a simple layout engine, see
examplel.c in the Joiner directory on the accompanying disk.)
As mentioned earlier, Amiga OS 2.0's GadToois library pro
vides ready-made layout subroutines. Fairly simple, Gad-
Tools menus work quite well and do not require any special
changes to the input event loop (unlike the gadgets part of
GadTools). The GadTools routines do pretty much what was
described in the previous section, except that they do not
currently support accelerator key symbols.
To create a menu, start with an array of NewMenu structures.
The NewMenu structure is much smaller than a normal
Menultem structure, but it contains all the fields you really
care about in terms of menu definition. It does not contain ex
act coordinates for the hit box, hidden fields used by Intuition,
and a lot of other scary stuff. For example, it offers no field to
point to the subitem list; subitems are defined by their type
and positioning in the array, rather than explicitly through
pointers. (You can see this in the source code for the second
example, example2.c.) Another nice thing is that if a second
window is opened, you can easily create another set of menus
from the same NewMenu array (you cannot have two win
dows sharing the same menu strip unless you are looking to
get Excedrin Headache#81000003.00217A3E).
To create the real menus, call CreateMenusA( ). The A
stands for the fact that this is a varargs routine, meaning that
it takes a TagList of extra parameters. (A word of explanation:
TagLists are new in 2.0, and are used all over to implement
library functions with variable numbers of arguments. They
are also totally beyond the scope of this article.)
After the menus are created, call LayoutMenusA( ) or
LayoutMenuItemsA( ), depending on whether you require
layout of a whole menu strip or just a single menu. At this
point the menus are ready to be used like normal menus.
With all this algorithmic generation of menus going on, a
surprising possibility arises, that of user-defined menus. I have
one application that reads in a configuration text file at boot
time that contains (among other things) all the text and bind
ings for all the menu items in the program. I can rearrange the
menus or convert them to a foreign language simply by edit
ing a text file. Given a basic parser and an extended menu
structure like the one described earlier, this is fairly easy. It is
just a matter of parsing the label of the menu and name of the
function, using that name to look up the address of the func
tion in a table, and then stuffing the function address into the
appropriate field. I leave minor details such as checkmarks
and mutual exclusion as an exercise for you.
GET TO WORK
After the menus are set up, your program must respond
to menu events. The required standard input event loop is
familiar to all Intuition programmers, but contains an oft-
overlooked subtle point: the use of the NextSelect field. In
tuition allows the user to make multiple menu selections us
ing the left mouse button while the right mouse button is
held down. In these cases, the menu hits do not come in as
individual messages, but rather as a single message with all
the menu items linked together. To catch all the menu hits,
your program must walk through this chain. Note thai if a
menu is hit twice, it only appears in the chain once. Also, if
the user happens to hit the menu again very quickly, while
the old chain is still being processed, the chain may be dis
rupted. Fortunately, this is not a problem because the
NextSelect field is an index rather than a pointer, so the worst
that can happen is a menu selection could be lost.
One innovative technique for making menu processing
easier is to use an extended menu structure, which adds extra
fields that the application can use at the end of the Menultem
structure. In fact, GadTools does this already, by adding an
extra field for application use every time it creates a menu
item. For example, every menu item could contain a function
pointer and have the main event loop call that function
whenever the menu is hit. For example, the New File menu
would point to the New File function. Say good-bye to com
plicated case statements!
In the final analysis, empowerment of the user is what it's
all about. Part of this process is leaping ahead of the user's
expectations, part is conforming to the user's decisions. Re
sponsiveness to the user's preferences regarding system-
wide typefaces and colors in your menus is part of this phi
losophy. Your challenge is to write programs with aesthetic
judgement and engineering elegance. ■
David Joiner is the author of Faen/ Tale Adventure and Music-
X, plus an artist, award-ivinning costume designer, and user-
interface expert. Contact him c/o The AmigaWorld Tech journal,
80 Elm St., Peterborough, NH 03458, or on BIX as talin.
6 April/May 1991
~
DIGGING DEEP IN THE OS
Looking Good
In 2.0
By Andy Finkel
SINCE THE RELEASE of Kickstart 2.02, unless you are
playing strange tricks, odds are that your 1.3 program runs
perfectly fine under Amiga OS 2.0. It may not look fine, how
ever; colors may be off, fonts may look strange, or other vi
sual defects may be apparent in normal operation of your
program.
Each change we at Commodore made to the operating sys
tem was made for a reason, to fix a bug or to add a feature.
Unfortunately, your program may have been depending on
the exact behavior of a particular bug or feature of 1.3 for
correct operation. In general, the problems you will face un
der 2.0 are those created by our removal of limits on the user's
choices. Via the expanded Preference editors, users now
have more control over the system setup and environment
and can change many more settings than under previous
versions of the OS.
As a result, you can no longer depend on the system de
faults to be constants; your program has to adapt to user se
lections. Of course, you could always take the easier route
and completely ignore the user's choices in favor of your
own hard-coded defaults. The first approach, however, is
more rewarding in the long run. Users like to see programs
that obey their choices.
The appearance of your product gives the user his initial
impression of the product, and in many cases of the Amiga
itself. If your program muffs its handling of fonts, colors, the
Workbench screen. Intuition rendering, and the cursor, it
may never get another chance. Users notice these things
right away and do not like them. Attention to these details
may mean the difference between winning a customer or
loosing a sale to a similarly featured but more attractive com
peting product.
FONT FIXES
Under 1.3, fonts were easy to handle and hard to change.
You could almost count on having one of two fixed-width
(mono-spaced) fonts by default: Topaz 8 or Topaz 9. Under
2.0, you are more likely not to have Topaz as your default
font. You may even have a proportional font as your default
screen-text font.
You can solve the problem in several ways. Ignoring the
user's wishes, you can explicitly set the font for your window
or screen to one your program can handle, such as Topaz 8.
A more desirable method is to check which font you get
when you open the screen or window and automatically ad
just to that font.
This can be difficult, if, for instance, you have a complex
screen layout or cannot handle proportional fonts. In this
case, Commodore suggests reverting to the system default
text font, which is guaranteed not to be proportional, if at all
possible. Only if you have no choice should you revert to a
hard-coded default of your own. (GfxBase — >DefaultFont
contains the user's choice of default mono-spaced fonts. If
you can't handle what you are given, look in this location. If
you can use the specified font, do so; otherwise, drop to a
default of your own.)
Handling fonts properly is not very difficult. The only in
correct choice, really, is to take whatever comes by default
and fail to adapt to it. (See "Menus for a New Generation"
for some specific suggestions.)
CYCLED COLORS
You will notice that we have changed the default color
scheme in 2.0, as well as which color registers contain the
light colors and which contain the dark. We redecorated on
the advice of top computer fashion designers: Gray is in for
this year and blue is out. Gray is sleek and businesslike. Gray
is the coming thing. While a few may make fashion faux-pas,
I do not expect any programs to be broken by this. After all,
the user has always been able to modify the default Work
bench colors. The register change, however, requires a bit
more explanation.
Under 1.0,1.1,1.2, and 1.3, the colors were a very saturated
blue background, white text, black, and orange (highlight
colors). When we made the decision to move to the more
professional background color (gray), the result was white
text on a gray background. So that the text showed up better,
we reversed white and black in the color registers, ending
up with (in order) gray, black, white, and light blue. This sim
ple decision has several important implications, especially
when you consider 2.0's three-dimensional look, which de
pends on the proper color relationships to give the illusion
of depth.
Unless your application specifies its own color scheme (dif
ficult on the Workbench screen), under 2.0 your 1.3 appli
cation will display white where there used to be black and
vice versa. If a 1.3 program creates a 3-D illusion with its own
color scheme, this change will reverse the look. Icons, of
course, will look somewhat different, to put it mildly. How
your application handles these problems depends on
whether or not it opens a custom screen.
If you do open a custom screen, you already have a con
siderable amount of control over your resolution, bitplane
depth, and so on, and can use this control to make your ap
plication look good under any OS version. The problem is
that Intuition would like some additional information that it i
The AW Tech journal 7
Digging Deep in the OS
did not require under 1.3. It would like to know which of
your colors you want it to use for text, for shadowing, and
for accent to give you the 3-D look. Without this information,
Intuition gives you a "mono-look" (very flat) set of system
gadgets.
When opening a custom screen using the OpenScreen( )
call, therefore, make sure you pass an Extended Screen struc
ture, which contains your choices for the screen pens Intu
ition uses for shadow, text, and shine pen colors. Your
gadgets will then be properly rendered as well. You can also
use these pen colors for your menus and your menus
IntuiText structure, so you can have your menus rendered
as dark text on a light background. Because you control the
number of bitplanes on your custom screen, you are also
spared some of the considerations that an application open
ing on Workbench has to face.
When on the Workbench screen, your icons are hard to
handle: While recoloring an icon in your program is easy,
designing an icon that looks good in both color combinations
is more difficult. Because the user can specify the number of
bitplanes to use, your program must adjust to handle one or
four bitplanes in addition to the usual two. You do not have
much choice here; if you open on the Workbench screen, you
have to handle its number of bitplanes. You can use the
standard methods of determining your environment, of
course, but it is up to your program to adjust. Do not hard-
code the number of colors; if you get fancy with scrolling
routines, make sure that they can adapt to changing condi
tions. By the same token, do not use GetScreenData( ) when
t commodore
AMIGA.MFMORY CHIP
Z56Kx 4*80 DIP
256Kx4-K0ZIPP
256K x 4-80 (Static for A3000)
1 MGx 8-80 SIMM
1 MG x 4-80 (Static for A3W0)
NEW FATTER AGNUS
Amiga Mouse
External Eli Density 1.52 MG Dr.
1.5 MG Insider Board for A1000
Keyboard for A10OO
A2000 Power Supply-
Power Supply A500 (Heavy Duly)
4 MG Bast: Board (for A500 w/2 Mg)
4 MG Bast Board (for A500 w/4 Mg)
Amiga Janus 2.0
2MG Expandable to 8 MG (FOR A2000)
4MG Expandable to H MG
40 MG Hard Card
40 MG HD (A500 W/512K)
GVP
4OMGHDforA500
40 MG Hard Card
100 MG Hard Card
A300] 4/0 28 MHz
33 MHz
$8.00
S9.50
SI 0.00
S79.00
•$42.95
$99.95
S40.IKI
S 189.95
$299.00
SI 39.95
S139.95
599.95
$249.95
$349.95
$29.95
■S210.00
S349.00
S549.00
S699.00
$699.00
S599.00
SS99.00
S1699.IH)
51995.00
* Special sale this month while supplies last
ASIAmptx Systems, Inc.
(No! affilialfd with AmpCX Corp.)
5344 JIMMY CARTER BLVD.. NORCROSS. GA 30093
(Orders Only) (800) 962-4489 ■ Fax (404) 263-7852
(Information A Prices) (404) 263-9190
opening a screen that is just like the Workbench screen. This
routine does not give you enough data. Instead, use the new
2.0 calls.
PERFECT INTUITION
Intuition rendering has not been spared changes, either.
Intuition used to be pretty relaxed about programs using its
private screen real estate, such as window borders, string
gadgets, and title bars. While it was not really supported, In
tuition let you get away with a lot in terms of programs put
ting elements in the borders, gadgets in the title bar, and
drawing into string gadgets. As of 2.0, Intuition aggressively
refreshes the screen area it owns, tending to erase or cover
things that wander into borders. You could experiment to
find the new limits of what you can slip by Intuition, but
instead you should rearrange things so they are not in In
tuition's private preserve. Taking the time to do so now will
help make future compatibility easier to maintain. (In reality,
Intuition goes to a great deal of trouble to simultaneously
render what it must and to avoid making your program's
elements lookbad. The easier you make it for Intuition, how
ever, the better.)
CURSES, TWO CURSORS
While the console.device has changed greatly for 2.0,
(growing a character map, switching refresh modes, sup
porting cut and paste), those alterations will probably not
cause your program problems. (I know I'm tempting fate say
ing this. Someone is probably already writing in with a
counter-example.) What may cause your program trouble is
the use of the cursor under 2.0.
To avoid problems, follow a simple rule: If you are using
the console.device and do not want to see the console,
device's cursor, turn the cursor off'. You would be surprised at
how many times this rule was not followed in the past. The
problem shows up in two places.
Under 1.3, a bug in the console.device gave no cursor on
SuperBitMap windows. To sidestep this, several programs
created their own cursor, which was all well and good, except
the programs forgot to turn off the console.devtce's cursor.
When we fixed the bug for 2.0, these programs suddenly had
two cursors and looked quite silly.
A second feature of the console.device causes a similar
problem: When a console window becomes inactive, the cur
sor is ghosted, which is fine, unless of course the application
has erased the cursor by means of a rectfill rather than turn
ing it off. In that case, when the window becomes inactive,
a little ghost cursor appears. (A kludge was later added to
prevent this in most cases, because it was a very common
mistake.)
While I have discussed only the common problems that
have prevented programs from looking their best under the
new operating system, there are many others to keep in mind.
We went to a fair amount of trouble to make the system itself
look better and more professional. Take advantage of these
new features and your programs will benefit as well. ■
Andy Finkel is Manager of Amiga Software at Commodore and
head of the 2.0 project. He's been with the company since before the
V1C-20 and is one of the people to thankfor approving the purchase
of the Amiga. Write to him cfo The AmigaWorld Tech Journal, 80
Elm St., Peterborough, NH 03-158, or contact him on B1X as afinkel
8 April/May 1991
_
Control Your ChannelsFor more flexibility in playing sound waveforms, learn to
access the audio hardware directly.
By Jeff Glatt
SUFFICIENT FOR MOST applications, the audio device,
with its linked lists, allocation keys, and I/O blocks, is often
too slow for musical use or syncing audio to complex ani
mation. In such cases, you can bypass the audio device and
deal directly with the underlying hardware.
REGISTER YOUR WAVE
The Amiga has four audio channels, each with five hard
ware registers. These registers are actual locations inside the
Amiga to which programs can only write. Reading them (that
is, moving data from them) will cause a system crash.
The first register of each channel holds a pointer to the
start of the waveform data (which must be in chip RAM). This
register is actually two separate word-length registers that
combine to form one register able to hold a long (32-bit ad
dress). Called the location register, it contains the address of
the point within the waveform at which you want the play
back to commence. With it, you can play only an excerpt
rather than the entire wave. Be sure, however, that the start
address is an even address (word-aligned)!
The second hardware register, the length register, contains
the number of words that will be played. The waveform's
length should be an even number of bytes, because the audio
hardware always fetches two bytes at a time, although it
plays each separately. (Each byte of a waveform is an eight-
bit linear sample point.) You should divide the number of
bytes that you wish to play by two and place the result in the
length register. (You divide by two because the audio hard
ware wants to know how many words, not bytes, to play).
The longest sample that the hardware can play automatically
is 65,535 words (131,070 bytes) long. To play longer samples,
you must change the location and length registers during a
channel's "audio-block-done" interrupt (more on interrupts
later).
The third register, period, contains the waveform's sam
pling period from which you determine the waveform's
playback rate. The sampling period of a waveform is the in
verse of its sampling frequency. If you want to play a wave
at the same pitch that it was "recorded" and know the sam
pling frequency, you can easily determine the sampling pe
riod with the formula:
period = (1 / sampling frequency in hertz) / .279365
The constant .279365 is a DMA hardware limitation im
posed by the Amiga; the system cannot support sampling
periods less than 124 (or sampling rates higher than 28,867
Hz). If you subtract from the resulting period value, the
waveform will play at a pitch higher than its original. If you
add to the period, the waveform will play lower than the
original pitch. Unlike with the location and length registers,
you can change the value in the period register at any time
while the channel is playing a waveform. Because the pitch
will rise or fall as you decrease or increase the period, you
can simulate the pitch wheel on a musical keyboard. You can
also simulate vibrato by repeating the following sequence:
1. Raise the period slightly.
2. Delay briefly.
3. Restore the period to its original value.
4. Repeat step 2.
5. Lower the period by the same amount as in step 1.
6. Repeat step 2.
7. Restore the period to its original value.
8. Repeat step 2.
Just make sure that the delays are the same length and the
period is always between 124 to 500.
If you do not know a waveform's sample frequency or pe
riod, you can still calculate the period register's value. First,
visually or mathematically isolate the start and end of one
cycle within the waveform and count the number of bytes
(sample points) in this cycle. Decide at what frequency in
hertz (pitch) you would like to play the wave. Now use the
formula:
period-(frequency In hertz / number of samples in a cycle) / .279365
The fourth register is the volume register, which holds the
playback volume. The range of acceptable values is from 0 ■
Tlie AW Tech journal 9
Control Your Channels
(the softest) to 64 (the loudest). Like the period register, this
register can be changed while the channel is playing. For ex
ample, you could lower the volume by one every fraction of
a second to slowly fade out a sound, build an entire envelope
generator, or achieve a tremulo effect by following the steps
for a vibrato and substituting the volume register.
Called data, the final register is where the audio hardware
puts the two bytes fetched for output. Usually, the channel
is playing back under the supervision of the DMA, so you
need not concern yourself with this register. The DMA au
tomatically feeds the next two bytes of the waveform to the
channel. When the DMA has sent the number of words that
you specified in the length register, the whole process starts
again back at the address in the location register. The DMA
repeatedly plays your excerpt until you stop the channel.
You do not have to start the channel with the DMA en
abled, however, if you prefer to feed the channel two bytes
at a time manually. To do so, you would place the bytes (a
word with the first sample point as the MSB) in the data reg
ister. After the hardware outputs the first word (at the rate
specified in the period register), the hardware tells you (via
an interrupt) that it wants the next morsel. You better be
ready with that data!
While this method is very CPU intensive and generally not
recommended, it comes in handy when you need to bypass
the DMA's constraints. With the manual method you can store
the waveform data in fast RAM, putting the sample points
anywhere you want (even out of order). You can also play a
waveform larger than 131,070 bytes without double-buffering,
because without the DMA the system ignores the location and
length registers, letting you decide where to start the sample
and how many points to output. No longer held back because
the DMA cannot deliver data to the channel faster than 28
KHz, you can directly play a wave sampled at a rate greater
than 28 KHz. As long as you are delivering data to the channel,
you can set a rate as fast as your code, and the Amiga's digital-
to-analog converter (DAC), can handle.
PROPER NAMES
Each of the hardware registers is an address inside the
Amiga, and the registers for each channel are adjacent in
memory, as shown in the following chart. The chart is set up
so that you can place it at the start of an assembly program
listing and use the symbolic names.
;Channe! 3
LOCATION-3
LENGTHL3
PERIODS
VOLUME—3
DATA_3
equ SDFF0DO
equ SDFF0D4
equ SDFFOD6
equ SDFFODB
equ SDFFODA
;Channel 0
LOCATION_0
LENGTH_0
PERIOD_0
VOLUME_0
DATA_0
;Channel 1
LOCATION_1
LENGTH_1
PERIOD_1
VOLUME_1
DATA_1
;Channel 2
LOCATION_2
LENGTH_2
PER1OD_2
VOLUME_2
DATA_2
equ SDFFOAO ;holds a LONG
equ SOFF0A4 ;holds a WORD
equ SDFF0A6 ;holds a WORD
equ SDFFOAB ;holds a WORD
equ SDFFOAA ;ho!ds a WORD
equ SDFFOBO
equ SDFF0B4
equ SDFF0B6
equ SDFFOBB
equ SDFFOBA
equ SDFFOCO
equ SDFFDC4
equ SDFF0C6
equ SDFF0C8
equ SDFFOCA
Before starting a channel, you must always initialize the
hardware registers. As soon as a channel is started, the sys
tem copies the hardware registers to a corresponding set of
backup registers. The DMA then uses these backup registers
to determine where to find the sample, how many words to
play, and so on. Immediately after the DMA transfers the val
ues to the backups, you can safely rewrite the location and
length registers. Each channel's audio-block-done interrupt
alerts you when the DMA is finished copying to that chan
nel's backups. The audio-block-done is the DMA's way of
saying, "I've just finished copying the hardware registers.
I've got what 1 need, so you can change them now." Later,
when the DMA finishes playing the number of sample words
specified in the channel's length backup register, it accesses
the hardware registers again.
Never change the registers while the DMA is copying to
the backups. Imagine the problems if you rewrote the loca
tion register before the DMA backed it up. The DMA would
copy the new waveform's address but the previous wave's
length. Who knows what the results would sound like! The
only safe times to rewrite the location and length registers
are when the channel is stopped (because the DMA will not
be fetching data) and immediately up on the channel's au
dio-block-done interrupt. To act upon the latter signal, you
must install an interrupt handler that will rewrite the regis
ters to the new waveform's address and length or signal an
other task to do so. You need not rewrite the registers,
however, if you want the DMA to play the same wave again.
Remember, you can rewrite the period and volume reg
isters at any time; the new values will take effect upon the
next data fetch (usually immediately to the human ear). If
the next wave's period or volume is different than those for
the wave the DMA is currently playing, do not rewrite the
period and volume registers at the same time you rewrite the
location and length. Because the new location and length do
not take effect until the previous wave is finished, you can
rewrite them as soon as the DMA copies. Wait until the new
wave starts, however, before you rewrite the new volume
and period. Your signal that the system has copied the new
location and length and is playing the next waveform is
when the DMA sets the channel's audio-block-done inter
rupt again. As long as your program is not in C, your inter
rupt handler should be able to change to the new volume
and period quick enough to avoid an audible glitch. Of
course, if the new wave has the same period and volume,
you can leave the requesters alone.
One application that may require you to change the loca
tion and length registers while playing one waveform is play
ing an 8SVX file. Most musical waves have a oneShot portion
(the initial "sound" of the wave, to be played once only) and
a repeat portion (the part that keeps "playing" until you stop
the note). You need to set up a channel's registers (before start
ing the channel) with the address, length, period, and volume
of the oneShot portion. When you start the channel, the DMA
will copy these values to the backups, start the actual audio
output, and set the channel's audio-block-done interrupt. At
10 April/'May 1991
Control Your Channels
~this point, Exec calls your interrupt handler. The handler can
now rewrite the location and length registers (while the one-
Shot is playing) with the address and length of the repeat por
tion. As soon as the oneShot is finished, the DMA will copy the
new location and length (thereby achieving a smooth, contin
uous transition to the repeat portion), and set the channel's
audio-block-done interrupt.
The system now calls your interrupt handler a second
time. At this point, the repeat has just started playing, so the
handler could adjust the period and volume. You do not
need to do so, however, because the 8SVX repeat segment
should have the same period and volume as the oneShot. For
all the subsequent audio-block-done interrupts, you can
leave the parameters alone, simply not change anything. The
DMA will continue "looping" on the repeat portion until you
stop the channel. Alternately, you can turn the audio-block-
done interrupt off upon the second interrupt. In this case,
you'll need to enable the interrupt each time before you re
start the channel.
WELCOME INTERRUPTIONS
Some addresses in the Amiga are write-only, while others
are read-only. You can move a value into a write-only ad
dress, but you cannot retrieve a value from it. The opposite
is true of a read-only address. Some registers, such as the
DMA, have separate addresses for reading and writing op
erations. Labeled dmaconr, the address to read the DMA is
SDFF002. The write-only address is $DFF096 and has the
symbolic label of dmaconw. As you would say in your listing:
dmaconw equ SDFF096
dmaconr equ SDFFOO2
To start or stop audio channels, you must write to dma
conw. To start a channel, bits 9 and 15 of the DMA register
must be set, as well as the enable bit of the audio channel
you want to start. The bit numbers of the DMA register for
the four audio channels are numbered 0-3, corresponding to
the audio channel numbers. You can start or stop several
channels simultaneously. For example, to start channels 1
and 2, you must move the value S8206 to address SDFF096
(move.w #$8206,dmaconw). To stop a channel, bit 15 of the
DMA must be clear, as well as bit 9, but the enable bit of the
channel that you wish to stop must be set. For example, you
would use the instruction move.w #$0001,dmaconw to stop
channel 0.'
To determine if a channel is playing, read the status of the
channel's enable bit at address dmaconr. For example, the
sequence:
move.w dmaconr,dO
Btst.1 #3,d0
bne.s ItsPlaytng ;branch if channel is playing
will tell you whether channel 3 is playing. Never read from
dmaconw or write to dmaconr, unless you want a guru error.
You should enable the audio-block-done interrupts as well.
Each channel has its own interrupt-bit enable in the interrupt
control register, intena. The interrupt control requester also
has separate write <$DFF09A) and read (SDFF01C) addresses:
intena equ SDFF09A
intenar equ SDFF01C
This register disables and enables the interrupts (allows or
disallows them from occuring), but does not tell you the cur
rent status of an interrupt. To check if an interrupt is occuring
or to reset the interrupt (as you should do at the end of your
handler routine), you must access the interrupt-request reg
ister, which has the following addresses for writing
(SDFF09C) and reading ($DFF01E):
Intreq equ SDFFO9C
intreqr equ SDFFO1E
Improper set up and handling of an interrupt can be
deadly. Always follow the proper three step procedure. First,
install an interrupt handler for each bit in the intena register
that you wish to enable. To so, initialize an interrupt structure
and pass its address and the intena-interrupt-bit number to
the Exec's SetIntVector( ). (The intena bits for audio channels
0-3 are 7-10, respectively.) Next, enable the proper channel's
bit in intena by setting bit 15, and the bit (or bits if you are
playing multiple channels) of the audio channel's audio-
block-done interrupts that you want. For example, to enable
interrupts for channels 0 and 1 use the command:
move.w #S8180,intena
To disable, clear bit 15 and set the channel's enable bit. The
following command disables channel 3's audio block done
interrupt:
move.w #$0400,intena
Finally, when an audio-block-done interrupt occurs on a
channel, Exec calls its handler. The handler resets its inter
rupt bit via the intreq register so that future interrupts can
occur. The bit assignments are the same as the intena register.
For example, the handler for channel 2 would need to reset
its bit as follows:
move.w #$0200,intreq
If you opt to fetch each word of data for a channel's data
register yourself instead of using the DMA, the audio-block-
done handler has an entirely different meaning. In this case,
the audio channel sets its interrupt every time that it needs
another word of data. The handler for a channel, therefore,
should supply the next piece of data. Of course, the handler
also must determine where to find the data and when to stop
the channel. You still need to install the handler via Set-
IntVector(), enable the channel's bit in intena, and clear the
bit in intreq at the end of the handler. The big difference is
in how you start the channel. When you write the DMA reg
ister, set bit 15 and the bit of the channel to start, but not bit
9. Make sure that the channel's data register already has the
first two bytes of the wave first sample as MSB. For example,
to start channel 0 without DMA fetch:
lea WaveAddress.aO ;the actual waveform data
move.b (a0) + ,d0 ;the first sample point
Isl.w 4=8.dO
move.b (a0) + ,d0 ;the next sample point ►•
The AW Tech Journal 11
Control Your Channels
move.w dO,DATA_0 ;move it to channel O's data register
move.! aO.WavePtr
;store the next sample's address for the handler
move.w #S8001,dmaconw ;start channel 0 w.o automatic data fetch
;When the audio block done Interrupt occurs, the handler
;needs to get the next two bytes at WavePtr, put them In
;DATA_0, increment WavePtr by 2, and clear the
;interrupt for that channel. The handler continues doing
;thls until it reaches the end of the waveform.
;lt then turns off its audio channel.
Your final consideration is the audio device itself. If another
program opens it, the audio device installs its own audio-
block-done interrupt handlers, which replace yours. There
fore, you must force the audio device not to allow any tasks
to use it. To do so, open the audio device before installing your
handlers to force the device to install its handlers first. Next,
lock all four channels with the audio device's CMD_LOCK
command so that the audio device will turn away all future
I/O requests. (If you cannot lock it, a task is already using the
device.) Install your handlers, saving the return addresses
from SetIntVector( ). These returns will be the addresses of
the audio device's handlers. When your program exits, rein
stall the audio device's handlers using SetIntVector( ). If the
original address was 0, however, skip this step. Finally, un
lock the four channels and close the audio device.
SOUND ADVICE IN ACTION
The example programs in the accompanying disk's Glatt
directory demonstrate how to play what appears to be an
8SVX sample with a looping portion and an 8SVX sample
with only a oneShot portion. I never really load the sample
data, however, as it is part of the program (loaded into chip
data when run). Because I chose to let the DMA feed the DAC
and not to do double-buffering, I must accept the 28 KHz rate
limit and the 131K sample-length limit. Therefore, neither
the 8SVX oneShot nor the looping portion may be greater
than 131K, however, the total of the two may.)
The examples have several audio routines that you can use
verbatim in your own C or assembly applications. (Note that
this example expects to run from the CLI for brevity. Nothing
about the audio routines themselves, however, requires this.)
The audio routines themselves (Audio.asm) are in 68000 assem
bly, but have C entry points so you can use them with C code.
In fact, I included both C and assembly versions of the example.
You must assemble the file Audio.asm, however, regardless of
which you use. Now, let's step through the example.
The program entry point is at the label _main. I first open
the DOS library and call SetupAudiof) once to setup the au
dio hardware. In SetupAudio( ) at label SI, I get the base of
the Exec library to access SetIntVector( ). At label S2,1 disable
the four interrupts for the audio channels prior to installing
my handlers; I do not want to be bothered by audio-block-
done interrupts until 1 am ready. At label S3,1 install the au
dio-block-done interrupt for audio channel 0. Note that dO
equals 7; 7 is the bit in the intena register that pertains to
channel 0. Look at the interrupt structure, intO. Its IS_CODE
field points to the function, audiolnt. When the audio-block-
done interrupt for channel 0 is set, the program calls audio-
int( ). Note that the IS-DATA field points to my own struc
ture called a LoopStruct that both PlayAudio( ) and
audiolnt() use. Each channel has its own LoopStruct. I set
the other channels up at labels S4, S5, and S6. At S7,1 set a
flag to indicate that the program is about to save the original
handlers that it may have replaced. If this bit is already set,
then I must have already called SetupAudio() without call
ing FreeAudio( ). This flag bit makes lets me call Setup-
Audio( ) and FreeAudio( ) safely and repeatedly, at any time.
I am now ready to play back audio samples. The sample
data is at the labels Wavelshot, Wavelloop, and Wave2shot.
The oneShot portion of the first 8SVX sample, Wavelshot is
512 bytes. Wavelloop is the Repeat section of the sample and
is 256 bytes long. The sampling frequency is 18000 Hz.
Wave2shot will be analogous to an 8SVX sample with a one
Shot portion only.
To convert the sampling rate (in hertz) to the wave's period
I use two routines. RateToPeriod( ) simply converts the rate
to a period in nanoseconds, so the program can use long mul
tiplies (no floating point) when calculating periods without
losing too much resolution. At label M4 in _main, I pass the
rate to RateToPeriod( ) and save it in d7. Now, when I play
this wave, I can transpose it anywhere from an octave up
( + 12 half steps) to an octave down ( — 12 half steps) using
the function TransposePeriod(). Note that a step value of 0
returns a period that plays the wave at its original pitch. At
label M5,1 play the wave at its original pitch on channel 0.
In PlayNote( ), at PI, I retrieve the custom chips' addresses
so that I can reference the intena, intreq, and dmaconw reg
isters. At P2,1 find the current channel's LoopStruct (size = 16
bytes), and from that structure, I determine this channel's
pointer audio register address. At P4,1 turn the channel vol
ume down in case the channel is playing another wave. To
simply stop the channel might cause a clicking noise as the
audio amp closes down too quickly. (You can hear this when
you use the audio device.) Note that I lower the volume by
half and then turn it off to minimize the click.
At P5, I stop the channel by writing its mask with bit 15
clear to the dmaconw register. Now, 1 can safely alter the lo
cation and length registers. After all, when the channel is
stopped, the DMA will not access the registers and audio-
Int() will not be executed. Note that if the location is 0, then
I exit PlayNote, effectively stopping the channel without
starting a new wave. (This is where StopChan( ) exits Play-
Note( ).) Also, note how at P7,1 divide the length of the sam
ple in bytes by two because the audio hardware needs to
know the number of words not bytes.
At P10,1 setup the channel's LoopStruct. When the chan
nel's block done interrupt occurs, audiolnt will check
LoopStruct to determine whether to play a repeat portion or
stop the channel after the oneShot portion. At Pll, I set the
DMA bit and the start bit of the mask in dO, so when I write
this to the dmaconw register, the channel will start playing.
(First, however, I clear any interrupt that might have occured
prior to my "stealing" this channel by writing my mask with
bit 15 clear to intreq.) Then at P13,1 set bit #15 of the mask
and write intena. Note that this enables the block-done in
terrupt for the channel, but does not execute it. (Writing the
same value to the intreq register subsequently would cause
an immediate block done interrupt.)
Finally, at P14,1 start the channel. The DMA grabs the val
ues that I placed in the hardware registers, puts them into
its backup registers, and causes a block-done interrupt (Exec
calls audiolnt( ) from a 68000 interrupt.)
The task halts while that interrupt is serviced. Let's take a
look at what audiolnt( ) is doing. Because this is an interrupt
Continued on p. 46
12 April/May 1991
Recycle Your SpritesPut more action on screen faster by reusing
your sprite channels vertically.
By Leo L. Schwab
A SHORT TRIP through The Amiga Hardware Reference
Manual (Addison-Wesley) will convince you that the Amiga
has a lot of hidden tricks. Many of these, however, stay hid
den because they are either poorly understood or not supported by the OS.
One of these well-kept secrets is that you can reuse sprites
vertically. The Amiga hardware can use a sprite channel for
the entire height of the display region. Further, this use need
not be continuous; the hardware can use the same sprite
channel to make several images appear at various locations
on the screen. The OS-supported method of reusing sprites
is through VSprites, which are part of the GELs system. Un
fortunately, VSprites are cumbersome and somewhat slow.
They work as fast as they want, not as fast as you would like.
Investigating the format of sprite data, I hit upon another
approach to sprite reuse that is friendly to the system, easy
to implement, and of reasonably high performance.
MINCING WORDS
Sprite data is laid out in chip memory as shown in Figures
1 and 2. The first two words of "image" data are position and
control information. As you can see, the format of these
words is identical to the hardware registers SPRxPOS and
SPRxCTL:
Bits Function
SPRxPOS (Image word 0):
15-8 Bits 7-0 of the vertical start (VSTART) position
7-0 Bits 8-1 of the horizontal start (HSTART) position
SPRxCTL {image word 1):
15-8 Bits 7-0 of the vertical stop (VSTOP) position
SPRITE—ATTACHED bit
Unused (set to 0)
Bit 8 of the vertical start (VSTART) position
Bit 8 of the vertical stop (VSTOP) position
Bit 0 of the horizontal start (HSTART) position
7
6-3
2
1
0
Immediately following this information are the actual
words of image data, which are treated in pairs. The first
word in an image pair is the low-order word (bitplane 0, so
to speak), and the second word is the high-order word. A
In-Memory Sprite Data Format
UWORD sprltedata[|-{
0x0000. 0x0000.
0x0550, OxOFFO.
0x1 EE8. 0xIFF8,
This data mustbe in CHIPRAM.
Firstsetofcontrol wordsImage data forfirstsprite
0x0000. 0x0000.
0x0550. OxOFFO,
0xF879, 0xFF23,
0x0000. 0x0000
Next set of control words
Image data for nextsprite
Terminating control words
Figure 1. The arrangement of sprite data In chip RAM.
SarilS-Register / Control Word Format,
SPRxPOS (wordO)
VSTART bits 7-0
15
SPRxCTL (word 1)
HSTART bits 8-1
8 7
VSTOP bits 7-0 0 0 0 0
15 8 7 6
SPRITE_ATTACHED
Unused
VSTART bit 8
VSTOP bit 8
HSTART bit 0
3 2 10
Figure 2. The format of position and control words.
pair of words forms one line of a sprite.
Here's where it gets interesting. Following the image data
are two more words. Ordinarily in the case of SimpleSprites,
these two words contain zeros, which indicate the end of the
sprite, and are the last two words of sprite data. These two
words are, in fact, position and control words for the next
use of the sprite channel. In format, they are identical to the
position and control words at the beginning of the sprite
data. It is perfectly legal to place new position and control
The AW Tech journal 13
Recycle Your Sprites
information here, followed by more image data, then more
control words and more imagery, and so on.
Usually, you manipulate the sprite data control words via
the graphics.library calls MoveSprite{ )and ChangeSprite( ).
Internally, MoveSprite{ ) calls ChangcSprite( ). Change-
5pritc( ) computes the position and control words, writes
them to the sprite data, and resets the appropriate hardware
registers to point to the top of the sprite data. At first glance,
you might think that you could simply reset the posctldata
field in the SimpleSprite structure to point to the successive
control words and call MoveSprite( ) to manipulate them.
Recall, however, that MoveSprite() calls ChangeSpritef ),
which resets the hardware's idea of the top of the sprite data.
Resetting posctldata and calling MoveSprite() could leave
the hardware pointing somewhere other than the top of
your sprite data.
If you are cautious about the sequence in which you make
the calls, taking care to call MoveSprite() for the "top" sprite
last, then you can use MoveSprite( ), although doing this
kind of bookkeeping is a bit cumbersome. The ideal function
would rewrite the control words in the sprite data and not
touch the hardware.
GET MOVING
The example program (see ms.c in the accompanying disk's
Schwab directory) contains a function, MyMoveSprite( ), that
fits the bill. Semantically identical to MoveSprite(), it com
putes the correct values for the control words and writes them
to the address contained in the SimpleSprite's posctldata field.
MyMoveSprite( ) does not touch the hardware. Its method for
computing the control words is rather interesting. At the hard
ware level, sprite coordinates are specified in low-resolution,
noninterlace pixel units. The origin of this coordinate system
is a point off the physical display in the upper-left corner. You
can bring sprites into a known coordinate system by adding
the offsets of the currently active View to the supplied x,y co
ordinates. MyMoveSprite( ) does this by adding the View
fields DxOffset and DyOffset to the passed x and y values, re
spectively. The View offset fields always represent low-reso
lution, noninterlace pixel units.
If a pointer to a ViewPort is also supplied, then My-
MoveSprite( ) treats the supplied coordinates not as lo-res,
noninterlace pixels, but as the pixel size currently prevailing
in that ViewPort (this is consistent with MoveSprite( )'s be
havior). Because sprites only relate to lo-res noninterlace
pixels, however, a program must convert the ViewPort co
ordinates to the closest possible sprite coordinates. My-
MoveSprite( ) accomplishes this by examining the Modes
field in the Viewport structure and scaling the coordinates
accordingly. If the ViewPort is high-resolution, the routine
divides the x value by two. If the Viewport is interlaced, the
y value is divided by two. (Be warned: This approach may
not work under Kickstart 2.0.1 have not investigated it yet.)
The offsets of the ViewPort relative to the View must be
added to the x,y coordinates, as well. In MyMoveSprite( ), I
add the DxOffset and DyOffset fields in the ViewPort struc
ture to the x and y values, respectively. These offsets are also
expressed in the pixel resolution prevailing in the given
ViewPort and must be converted to sprite coordinates.
Once the routine computes the final sprite coordinates, it
creates the position and control words in a straightforward,
if slightly clumsy, operation. The position word (word 0) con
tains bits 7-0 of the y value (VSTART), and bits 8-1 of the x
value (HSTART). Therefore:
pos = <VSTART « 8) + (HSTART » 1);
(assuming HSTART is in the range 0-511.)
The control word (word 1) is more complicated. The high
eight bits, which are bits 7-0 of the VSTOP value, are easy:
ctrl = (VSTART + spritehelght) « 8;
Three bits require specific locations. Bit eight of VSTOP
must be written to bit one of the control word:
It ({VSTART + spriteheight) S 0x100)
Ctrl ,=2;
Bit eight of VSTART belongs in bit two of the control word:
If {VSTART & 0x100)
Ctrl =4;
Bit zero of HSTART must reside in the control word's bit zero:
Ctrl =HSTART & 1;
Finally, you should preserve the SPRITE^TTACHED bit.
This is an OS-supported trick up the Amiga's sleeve that per
mits the use of 16-color sprites. While creating and using at
tached sprites is beyond the scope of this article, MyMove-
Spritef ) preserves the SPRITE_^TTACHED bit.
Ctrl = spriteptr->posctldata[1J & SPRITE__ATTACHED;
(Be careful: Unlike MoveSprite( ), MyMoveSprite() does not
properly support the SPRITE_ATTACHED feature. If you
use MyMoveSprite( ) with attached sprites, you will need to
call MyMoveSprite( ) for both sprites in the attached pair.)
Having created the position and control words, MyMove-
5prite( ) writes them to the sprite data:
spriteptr- >posctldata[0] = pos;
spriteptr- >posctldata[1]-Ctrl;
The sprite hardware will pick up this change when the
sprite DMA channel reads the new control words, and the
hardware moves the sprite to the new location.
GO WITH THE FLOW
The theory sounds great, but how do you put it to practical
use? Set up your sprite image data in chip RAM starting with
a pair of control words, followed by the first image, then two
more control words, then another image, and so on. After
the last image, place two final control words containing the
value zero to tell the sprite DMA hardware to stop fetching
sprite data. Next, create a SimpleSprite structure for each im
age you embedded in the sprite data. For each SimpleSprite
structure, you initialize the posctldata field with the ad
dresses of each pair of control words. This way, you have a
SimpleSprite structure managing each sprite image embed
ded in your sprite data.
Now, allocate a sprite channel with the graphics call
GetSprite():
if (GetSprlle (Stopsprite, -1) < 0)
error (NO_SPRITE);
Use the graphics call ChangeSprite( ) to point the system
at the top of your sprite data and tell the hardware to start
processing it:
ChangeSprite (vport, Sttopsprite, spritedatatop);
U April/May 1991
Recycle Your Sprites
~
"
At this point, at the very least, the first sprite in your sprite
data will be visible. If you preset all the successive control
words as well, the rest of your images will appear, too. Fi
nally, you can call MyMoveSprite( ) on any one of the
SimpleSprite structures, and the corresponding sprite imagewill move to the desired location.
Alternatively, you can initialize the positions of all the
sprite images by calling MyMoveSprite() for each of them
before calling ChangeSprite( ). When you finally call
ChangeSprite( ), all the sprite images will immediately ap
pear in their specified locations.
If you want to be sure all the sprites move simultaneously,
you can double-buffer your sprite data. To do so, you create
and maintain two identical sets of sprite data, then call
ChangeSprite( ) to display one set and MyMoveSprite() to
modify the other. When your modifications are complete,
you call ChangeSprite() to display the newly modified set,
and start changing the old set with MyMoveSprite( )... andrepeat.
TRIP UPS
The most obvious limitation with reusing a sprite channel
is that you must not supply MyMoveSprite() with coordi
nates that will cause the imagery to collide vertically. The
highest position a sprite image can occupy, therefore, is one
line below the last displayed line of the previous sprite image
on the same channel. Remember: The sprite DMA hardware
moves through your sprite data sequentially as the video
beam moves down the display. Because you cannot make the
video beam back up, you can only specify locations on suc
cessively lower display positions. While you have complete
freedom in horizontal positioning, subsequent images in the
sprite data must appear in successively lower positions on
the screen. Because of the hardware set up, successive sprite
imagery must be vertically separated on the screen by at least
one blank line.
The function MyMoveSprite() modifies the control data
directly. This modification can theoretically happen while
the hardware is reading the data. This may result in the sprite
imagery being corrupted or disappearing for one video field.
You can avoid this problem by using video beam avoidance
techniques or by double-buffering your sprite data.
Despite these limitations, this is a useful trick that can help
make certain graphic effects easier. For example, you can use
this feature to create a multiplane side-scrolling star field us
ing nothing but sprites. Thus, you can have a very effective
scrolling background of stars, and still have the whole stan
dard display available unhindered. (European demo pro
grams do this all the time.) Use it to add that little extra
embellishment that lets your program, and the Amiga, stand
out just a bit more. ■
Leo L Schivab is the principal programmer behind Disney Pre
sents. . .The Animation Studio and creator of many PD screen
hacks. He can frequently be seen at computer shows wearing a cape
and terrorizing IBM reps. Contact him do The AmigaWorld Tech
Journal, SO Elm St., Peterborough, NH 03458 or on BIX, People-
Link, or USENET as ewhac.
ARRIBA HD 20internalfor the AMIGA 500[
714-283-0498
800-942-9505
15448 FELDSPAR DR., CHINO HILLS, CA. 91709
"We believe there is a cure for MSDOS"
Interface:6-layers Multilayer
SMD-technology
Auto config
Autoboot capability with Kickstarl 1.3
Compatibility with internal + external expansions
20MB-Harddisk:16Bit-AT-Task-File-lnterface
23 ms average seek-timeNo external power supply
Pre'spect Technics Inc.
PO. Box 670. Station H
Montreal, Quebec H3G 2M6
Phone:(514)954-1483
Fax: (514} 876-2869
MASTER 3A-1 Disk Drive
$79.95
GOLDENlMAGE
HAND SCANNER MASTER 3A-1D
RC500 (A501 clone) 2-8 MB BOARD (A2000)
OPTICAL MOUSE
OPTO-MECHANICALWF. WILL BEAT ANY PRICK ON ANY OF
THESE PRODUCTS.
WE WILL BEAT ANY ADVERTISED PRICE!
AND JUST ABOUT ALL UNADVERTISED PRICES ALSO.
MEMORY UPGRADESDRAMS
64x4 - 12O/1OO/80/70
256x1 -120/100/80/70
256x4-100/80/70
265x4- 100/80 Page Zip
IMx 1 -100/80/70
SIMMS1x8-12/10/80/70
4x8 - 80/70
GVP SIMMS TOO!
A3000 STATIC ZIPS
1x4-80/70 $42.95
256x4-80 $6.95
"FOR SOFTWARE GO TO
THE REST.
FOR HARDWARE CALL
THE BEST!!!"
Why purchase from a large
company where YOU arc
just a number? Buy your
AMIGA hardware from
guy's that own AMIGA'S
and know how to use them.
INTERNATIONAL ORDERS
SAME DAY SHIPPING
UPS ■ RED, BLUE. GROUND
C.O.D. ACCEPTED ALONO
WITH
1 -800-942-9505
TheAWTechJournallS
GRAPHICS HANDLER
The Deep-Bitmap
IFF Standard
By Perry Kivolowitz
FOR ALL OF its generality, the original IFF ILBM specifi
cation was closely tied to the specifics of the Amiga's native
display capabilities and did not accomodate the added data
requirements of true color image processing. To keep pace
with the times, ASDG has (in cooperation with others, most
notably Carolyn Scheppner and Justin McCormick) devel
oped and established a standard for deep bitmaps, as well as
for images with 6 to 8 bitplanes as a special case.
While some of this new code has been adopted by Com
modore as a standard, much is convention that ASDG has
developed. By presenting it publicly, I hope to garner sup
port for these ASDG conventions so that they may join the
endorsed standard. They are not a complete solution, how
ever; the current deep-bitmap standard is just barely ade
quate. As you will see, work towards standardization must
still be done in some areas (such as Alpha channel support),
and in others, assumptions were made that will limit the ex-
tendability of the standard.
IFF EXCAVATIONS
The original IFF ILBM (InterLeaved BitMap) specification
provided for at most eight bitplanes of image data. (For a
thorough discussion, see the Amiga ROM Kerne! Manual: In
cludes and Autodocs from Addison-Wesley.) The format is
called interleaved because the data is stored by interleaving
a single scanline's worth of data from plane 0 followed by a
single scanline's worth of plane 1, and so on. From the top
of the image (beginning of the file) to the end of the image
(end of the file), the data comprising each scanline's planes
is interleaved across the number of lines in the image.
No one plane has color significance attached to it. Rather,
one bit in each plane contributes to an index into a color map
(CMAP) that, in turn, tells you which color should be dis
played at a given pixel. Images written in the original IFF spec
ification, therefore, are mapped. The maximum number of
significant entries in a color map is defined by 2hlmjPdi;f"h. For
example, a 3-bitplane-deep image should have at most eight
(21) entries in its CMAP chunk. For some new software and
hardware, however, the traditional CMAP chunk does not
make sense. For example, a CMAP for a 24-bit color image
would be 50,331,648 bytes long, an unweildy and ridicu
lous size.
(CMAPs are notorious trouble spots for programmers. Re
member that each CMAP entry is three bytes long, and all IFF
chunks begin on word boundaries. If a CMAP length comes
out odd, you should write its chunk length as odd and append
a single padding byte after the entire chunk.)
The altered IFF standard allows for deep bitmaps with 12 or
16 April/May 1991
more bitplanes where the actual number of bitplanes must be
a multiple of three. Under this rule, 12-, 15-, 18-, 21-, and 24-
bitplane formats are completely acceptable deep-bitmap IFF
formats. The standard begins at 12 bitplanes because it fits nat
urally with the Amiga's 12-bit palette width and because no
developers voiced a desire to begin at fewer than 12 bitplanes.
The upper limit, 24 bitplanes, is a practical limit. You can
exceed it, but no current devices take advantage of the in
formation. At ASDG, for example, the IFF readers will cor
rectly process an IFF file deeper than 24 bitplanes. This code
simply discards (as yours should) the least significant bit
planes beyond 24.
The same applies if you want your application to process
fewer bitplanes than are supplied: Discard the least signifi
cant planes beyond the depth you are willing to accomodate.
Note that you will still have to correctly interpret any Color
Look-Up Table (CLUT) chunks which may be present (more
on CLUTs later). Do not get too comfortable with this
method; it is the least appealing for color reduction.
According to Commodore mandate, the file's bits must be
ordered as an interleaved bitmap from the least significant
bit to the most significant bit, for each of the red, green, and
blue values. For example, for a 12-bitplane image, you would
specify planes 0 through 3 of red data for scanline 0, followed
by planes 0 through 3 of the same scanline's green and blue
data, respectively. You repeat the same order for each suc
cessive scanline until you specify the entire image. Note that
you must specify to which color each plane in the data cor
responds, but that you need not when describing a bitmap
in the original IFF standard. In a 12-bitplane image, the first
four planes per scanline correspond to the red information
in the image. Therefore, without using a CMAP you can as
semble the image and have it appear reasonably correct. This
is an example of noncolor-mapped image data.
The first limitation in the current deep-bitmap standard is
that it cannot support formats in which the component
colors do not have the same resolution. All bitmap depths at
12 or beyond must be a multiple of three with each color
component using exactly one-third of the image data. This
is unfortunate because some color models lend themselves
to nonequal color distributions. This is not a major restriction,
however, because IFF was defined as working within the
RGB color model. Clearly, if you need nonequal RGB com
ponents, making the bitmap depth triple the deepest desired
component depth and padding any unused planes will side
step this limitation. Some alternative image file formats, such
as TIFF, allow you to specify the individual depth of each
color component directly. I and my ASDG coworkers suggest
'
~
that a similar capability be implemented in IFF.
A GLUT OF CLUTS
To determine the color of an individual pixel in the original
specification, you had to assemble the component planes for
a given pixel into an index number, then read out the pixel's
actual color from the color map table entry specified by the
index number. The ability to perform some type of color in
direction is extremely important to many applications even
when dealing with such noncolor-mapped images as deep
bitmaps. The CLUT chunk provides this color indirection ca
pability. CLUT chunks have the fixed structure shown below:
struct = CLUT {
ULONG Type;
ULONG Reserved;
UBYTE LUT[256];
};
The fact that this structure is fixed is the second limitation
in the deep-bitmap standard. Specifically, the CLUT chunk's
fixed structure limits CLUT resolution to eight bits and the
bitmap depth for which CLUTs are usable to 24 bitplanes.
The following six CLUT types are currently defined:
^define CLUT_GREEN = O
#define CLUT_MONO> 0
#define CLUT_RED> 1
^define CLUT_GREEN> 2
#define CLUT_BLUE> 3
^define CLUT_HUE> 4
^define CLUT_SAT> 5
Of these, ASDG (and all developers I know) never uses the
hue and saturation chunks. ASDG uses the monochrome
CLUT to filter gray scale image data and the red, green, and
blue CLUTs to filter the corresponding type of color data. The
effect of the color balancing controls in ASDG's Art Depart
ment programs were implemented using CLUTS. I prefer
this to modifying the data to reflect, for example, an increase
in brightness, because you can easily reverse modifications
to a CLUT but not to the raw image data.
When your program finds a CLUT, it uses the CLUT as a
filter for a specific segment of the image data. For example,
the red CLUT color maps only the red color data.
As indicated above, CLUTs always have 256 entries even if
the bitmap to be stored has fewer than 256 shades (8 bitplanes)
of each primary color. In such cases, take care to fill the CLUT
uniformly, using the entire range of indices (from 0 to 255). The
entire CLUT must be valid through indices 0 to 255. As a result,
An eight-bit gray-scale (deep-bitmap) image.
your program may have to do some interpolation.
When interpreting raw image data that is less than eight bits
wide per primary color, you must expand the raw data to the
range of 0 to 255 to determine which CLUT entry to use. For
best results, use a method that allows both a pure dark (0) and
a pure light (255). Simply shifting left by a number of bits does
not accomplish this. ASDG uses the algorithm:
Let D be a red, green, blue, or gray component of a pixel.
D is N bits wide where 4<N <8. Then Index = (D«
(8-N)) | (D»(2N-8))
For example, a red value of 0 from a 12 bitplane-file be
comes index 0 into the red CLUT (if present), but a value of
15 becomes 255, giving you the the pure light and dark you
need. Simply shifting a value of 15 left by 4 bits gives you
240, not 255.
In some rare cases you may want to use both a CLUT and
a CMAP. For example, you could store a four-bitpiane gray
scale image with both a MONO CLUT and a CMAP. The
CMAP might map the 16 possible color registers to gray
scales. Having a CMAP present as well as a CLUT allows any
standard Amiga viewer program to read the image. If both
a CLUT and a CMAP are present, the program should always
give precedence to the CLUT. CLUTs are optional, but if pre
sent, they should be interpreted. If they are not present, your
program should assume a linear or neutral setting.
The hue and saturation CLUTs can interact with the in
dividual color CLUTs. No order for processing CLUTs (other
than order of appearance) has been defined, leaving room
for alternative methods of interpretation and, as a result, in
compatible files. While this is not currently a pressing prob
lem (no one I know of uses the hue and saturation CLUTs),
a definite processing order should be discussed and defined.
In an IFF file, the chunk length of a CLUT chunk should
always be 264 bytes. While not yet endorsed by Commodore,
the extended CLUT structure
slruct = CLUT {
ULONG Type;
UVVORD NEntries;
UBYTE NBils;
UBYTE NBytes;
UBYTE LUT[ ];
};
is one with which we can grow. The CLUT would have the i
The AW Tech Journal 17
Graphics Handler
number of entries specified in the NEntries field. Each entry
would be NBytes wide, of which the NBits least significant
bits would be counted. This proposed structure has the ben
efit of being backwards compatible with the older CLUT def
inition when the CLUT width is one byte. New CLUT types,
such as those below, can be defined to differentiate a vari
able-width CLUT from the original fixed-width CLUT:
^define CLUT_VAHIABLE_W1DTH_GREEN- 16
#define CLUT_VARIABLE__WIDTH_MONO> 16
^define CLUT_VARIASLE_WIDTH_RED> 17
Adeline CLUT_VARIABLE_WIDTH_GREEN> 18
#de)lne CLUT_VAR1ABLE_WIDTH_BLUE> 19
^define CLUT_VARIABLE_WIDTH_HUE> 20
#define CLUT_VARIABLE_WIDTH_SAT> 21
BODY AND BMHD ISSUES
Apart from the bit ordering, writing the BODY chunk of a
deep-bitmap IFF file is the same as writing any other IFF
BODY. Remember, however, that every plane and scan line
must begin on a word boundary. As the original IFF specifi
cation says, "The fields w and h (of the bitmap header) in
dicate the size of the image rectangle in pixels. Each row of
the image is stored in an integral number of 16-bit words."
The intended use of the bitmap header's pageWidth and
pageHeight fields, specifying a suggested display size, does
not make the transition into handling large nondisplayable
bitmaps. ASDG always sets these to the very safe 320 x 200
size. With deep bitmaps, w and h specify the size of the im
age, not pageWidth or pageHeight. ASDG does not use the
x and y fields, which specify the image's position in relation
to a larger enclosing image, setting them to 0.
The xAspect and yAspect fields can be helpful in deter
mining if the image is intended to be displayed in an inter
laced format. For Amiga-displayable images, however,
desired screen formatting information should come from a
CAMG chunk. In general, you should set xAspect and
yAspect as accurately as you can so reader programs that
monitor these fields receive valid data. Note that programs
that do not pay attention to these fields should be prepared
to handle nonfactored aspect ratios. For example, a reader
program should be able to handle an aspect of 20 to 22 or 100
to 101, as well as the prime-factored 10 to 11. Make sure your
image reader, however, can handle compression types other
than 0 and 1 gracefully. If your program cannot understand
a compression type, it should report this to the user rather
than load the file and assume a known type of compression.
CAMG AND ID CHUNKS
Unlike for standard images, you do not need a CAMG
chunk for a deep-bitmap image. In fact, the absence of a
CAMG chunk may be the only way you can tell the type of
data contained in the given file. For example, the only way
to tell that a 6-bitplane file is a color-mapped 64-color (dis
tinct) image is by noting that CAMG chunk is either absent
or specifically does not say the image is HAM or Extra_Half-
brite. By the time your program reads the BODY chunk it
should know exactly what type of image it is reading and
how to interpret the image.
Some IFF writers out there, such as DeluxePaint III (Elec
tronic Arts) and several public-domain programs, create con
fusing CMAP chunks when writing Extra_HaIfbritL' (EHB)
and HAM images. When we save an EHB image, we save
only 32 color registers because the second set of 32 are de
fined by the first. If you wish to write all 64 color registers,
make sure you write the correct values in the latter half.
DeluxePaint III, for example, places random numbers in the
second 32 registers which confuses nonAmiga IFF readers if
they do not notice the CAMG EHB flag. When saving HAM
files, we save only 16 colors registers because this is all that
may be used. (Some PD programs save 64 color registers for
no apparent reason.) Remember, if you are saving a HAM or
EHB image, make sure you include the appropriate CAMG
chunk so that 6-bitplane HAM and EHB files can be distin
guished from 64-color color-mapped files.
Two IFF chunks (ANNO and AUTH) can be used to insert
comments into an IFF image file. ASDG strongly recom
mends that you use the ANNO chunk to insert a string that
lists the identity of the last program that wrote this file. You
can make the AUTH chunk available to the user for other
uses such as the artist's name. When writing an IFF file, we
strongly recommend that you never carry forward another
program's ANNO chunk. Doing so would make keeping
track of the last writer impossible. Being able to determine
which program wrote the image will help if your program
finds file incompatibilities.
THE NEWTEK CONNECTION
NewTek's Digi-View 3.0 software stores 21-bitplane raw
image data in a form completely compatible with the deep-
bitmap standard. Unfortunately, it writes the bits in the op
posite order from Commodore's standard. Even worse, you
cannot determine if you are processing one of these files until
the erroneous results appear on the screen. Thankfully, Digi-
View 4.0 and the Video Toaster's software write their bits in
the Commodore-endorsed order and should be compatible
with the extended deep bitmap specification.
The differences are only semantic when it comes to two
newer variations on the IFF format supported by ASDG and
NewTek (but not endorsed by Commodore). While named
differently (AHAM and AREs'for ASDG; Dynamic HAM andDynamic Hi-Res for NewTek), the file formats are identical.
ARES (Dynamic Hi-Res) stores the image as a standard high-
resolution image (bit set in CAMG) with four bitplanes. The
format uses a standard CMAP chunk, plus a new chunk
called the CTBL prior to the BODY. The CTBL contains one
16-color palette (32 bytes, each color occupying a 16-bit word
with the color information defined in the form of a 12-bit
RGB triple) for each scanline in the image. AHAM (Dynamic
HAM) stores the image as a standard HAM image (bit set in
the CAMG) with 6 bitplanes. Again it contains a standard
CMAP chunk and a CTBL chunk prior to the BODY. To sum
marize these modes: If you find a CTBL chunk, it means you
are processing a dynamic mode file. Check the CAMG to fig
ure out which type of dynamic file you are working on.
Although it is not required, we strongly recommend that
you place the darkest color of each palette in the color reg
ister 0 position. This provides for a less distracting side border
when displaying nonoverscanned "dynamic" images.
Should you need more information on the emerging deep-
bitmap IFF standard or wish to offer suggestions, speak up in
the amiga.dev/iff conference on BIX. I'll be waiting for you. ■
Pern/ Kivolowitz is co-founder of ASDG Inc., which specialize*
in color image processing. Contact him at The AmigaWorld Tech
journal, 80 Elm St., Peterborough, NH 03458 or as perry on BIX.
IS April/May 1991
° This is the most cost effective way to
increase the speed of your computer.
AdSpeed™!
~
AtiSpeed
ICD expands its line of innovative enhancement products for the Amiga®with the
introduction of AdSpeed, a low cost, full featured 14.3 megahertz accelerator for
all 68000-based Amiga computers.
ers from other accelerators by using an intelligent I6K static RAM
cache to allow zero wait state execution of many operations at twice the regular
speed. All programs will show improvement. No 68000 or 68020 accelerator
without on board RAM will make an Amiga run faster.
AdSpeed continues ICD's tradition of providing the best product available.
These are some of the features that set it apart from the rest:
• Works with all 68000-based Amiga computers, including the 500. 1000. and
2000.
• Simple no solder installation — just remove the computer's 68000 and plug
AdSpeed into its socket.
• Low power, high speed CMOS 68000 CPU for full 100% instruction set com
patibility.
• Software selectable speeds, with a true 7.16 megahertz mode for IOO# com
patibility. Switches speeds on the fly without rebooting the computer.
• 32 kilobytes of high speed static RAM — 16K of data/instruction cache and
I6K of cache lag memory.
• Full read and write-through cache for greatest speed.
• Bus monitoring to prevent DMA conflicts.
• ICD's famous quality, dependability, and support.
• Worlds smallest 68000 accelerator. (Photo above is actual size).
ICD, Incorporated 1220 Rock Street Rock ford. IL 61101 USA
(815) 968-2228 Information (800) 373-7700 Orders (815) 968-6888 FAX
AdSpeed h a trademark of (CD, Inc Amiga is a registered trademark of Commodore-Amiga, Inc.
REVIEWS
CygnusEd Professional
Release 2.11
Flexible and function filled.
By Tim Grantham
PREVIOUS VERSIONS OF the
CygnusEd Professional (CED) text edi
tor deservedly had a loyal following of
Amiga programmers. Release 2.11
brings them good news: It adds user-
definable colors, a high-speed global
search-and-replace, support for alter
nate fonts, and a wonderful Undo/
Redo capability. It also significantly en
hances many features of previous ver
sions, including macros, file security,
and AmigaDOS/ARexx support.
Potential new users, however, may
not be able to overlook the limited dis
play choices offered by the program.
CED can display up to only ten views
at a time of the files (or variations of
one file) being edited. Ten views may
sound like a lot, but it's a ceiling I've
bumped my head on several times.
Even more annoying, CED forces all
views into one screen or window. You
can resize the views vertically down to
one line of text and a title bar, but they
eat up a fair amount of screen real es
tate. I prefer text editors that let me
view a full screen of text for each file
in memory, such as Rick Stiles's share
ware editor UEdit. CED does have an
auto-expand feature that automatically
resizes the inactive views to provide
the maximum possible size for the ac
tive view, but I find the clutter of inac
tive views an irritation, even in hi-res.
DESIGN YOUR OWN
CED's limitations in display lie in
sharp contrast to the rest of the pro
gram, which is a model of flexibility.
To customize it, you can create, load,
and save macros, then bind them to
any key. You can also create multiple
preference files that contain settings
for screen size, display colors, font,
and so on, plus edit modes, save
mode, task priority, macro definitions,
tabs, and many other variables. A2024
monitor owners can increase the
screen size up to 1000 by 800, as well.
You can also add functions to CED
using its extensive ARexx command
set. For example, I wrote an ARexx
script that positions my CED text cur
sor at the location of each error in my
Aztec C source code and allows me to
correct the error before moving on the
next one. Once I'm satisfied with the
corrections, I can start the cycle again.
Plus, the included utility CB2RX lets
you add AmigaDOS clipboard support
to any program that speaks ARexx.
CED makes life easier for program
mers in many other ways. It has a
find-matching-bracket function, col
umnar block cut and paste, backward
searching abilities, user-selectable text
scrolling speed, selectable tabs (fixed
or custom width) versus spaces, jump
to line (an essential command for my
ARexx), split views, and the ability to
edit binary files. If you often type com
mands in the wrong case, you'll appre
ciate that CED lets you toggle the
word at the cursor between upper-
and lowercase.
CED Release 2.11 adds new file,
print, and font requesters. One of the
best I've used, the file requester has
several good features: the ability to
hide or show files in the listing using
both AmigaDOS and Unix wildcard
characters, a full listing of all physical
and logical devices, the ability to select
multiple files, the display of file sizes,
and the use of keyboard equivalents.
On the negative side, CED doesn't
highlight selected files and does cache
the listing. The latter provides fast dis
play but doesn't keep up with changes
to the directory's contents. You can
force a reread of the directory with a
gadget for that purpose. As a nice bo
nus, ASDG includes full documenta
tion for the freely distributable run
time library used to create the file re
quester. Unfortunately, the print re
quester is almost identical to the file
requester, which can cause confusion.
Macros in CED 2.11 can now collect
data entered from requesters and can,
like AmigaDOS and ARexx commands,
be bound to any key. I created one
macro to get around a CED limitation:
The macro combines two commands,
Open New and Open, so that I can
load a new file into a new view with
one keystroke. A helpful addition
would be a way to get a listing, by key,
of all macros from within CED.
The Undo/Redo command is terrific.
It lets me unwind almost all changes
to a file in memory, right back to the
beginning if necessary, which I've al
ways wanted to be able to do. The
catch here is memory. According to
ASDG, each operation on the text,
even entering a single character, con
sumes about 50 bytes from the undo
memory pool. Multiply that by the
number of files loaded into CED and
you begin to see the RAM required.
But if you've got an elephant's mem
ory in your machine, go for it.
Getting files in and out of the pro
gram is easy. When run from the CLI,
CED attempts to load an environment
(preferences) file with the same exten
sion as the hie to be edited. If, for ex
ample, I run CED with a file called
example.ts as an argument, CED will
look for an environment file called
sxeddefaults.ts, configure itself with
that file, and then load example.ts.
This enables you to configure CED to
work like the editor used to create the
loaded file automatically. If you prefer,
you can restart CED with a hot-key
combination, providing you shut the
program down appropriately. So that
you don't forget to save your files, Au-
tosave lets you set a time-lapse re
minder. If you save files with icons,
you can set the icon tool from CED.
Should your system crash before you
save, RecoverCEDFiles, a supplied util
ity, searches through memory for CED
text files orphaned by the crash. 1 only
wish the program's installation script
let me specify where I want to put the
CED executable and its associated files.
CED supports limited printing capa
bilities, as is true of most text editors.
You can set typestyles using function
keys, but cannot display them. Tabs can
be converted to white spaces and vice
versa. Print function output can be sent
20 April/May 1991
~
~
to any AmigaDOS device or file.
SNAKES IN THE GARDEN
The program is very robust: It works
as advertised without bugs. I do have
a few complaints about its design, be
sides the display limitations. For exam
ple, the mark-columnar-block feature
is limited in maximum size to the size
of the current screen of text. If you at
tempt to mark text outside of the cur
rent display area, by dragging the
pointer to the top or bottom, the text
scrolls but the highlight area does not
expand to encompass it. An equally
frustrating inconsistency is the use of
the asterisk as a wildcard.
CED features extensive ARexx sup
port, with almost every menu selection
callable from an ARexx script, plus
other commands that aren't in the
menus, such as Jump To Column. I
found the ARexx implementation
strategy a little odd. CED uses the ex
act names of the menu items as the
names of the ARexx-callable com
mands. While this might make most
scripts easier to read, it means that you
cannot directly call menu items that
change their texts during operation.
For those items you must resort to a
"menu n n n" call, where the argu
ments to menu specify the menu,
menu item, and menu sub-item, re
spectively. In a similarly odd vein is
the "status n" call, in which n is a
number that varies according to which
piece of status data is required. Why
not simply have a call to status return
a structure describing the complete
CED environment? Most annoying,
CED currently provides only one
ARexx port name: rexx.ced. This causes
a problem if more than one copy of
CED is running. The single port also
makes it difficult for more than one
program at a time to talk to CED.
The manual says that CED requires
Workbench and Kickstart 1.2 or later.
Apparently, later does not include 2.0.
Running CED under Kickstart 36.207
and Workbench 36.77 (Amiga OS 2.02)
did not cause any crashes, but text dis-
Memory. CED dais have sn 'auto-expand' feature that nut anatically resizes
(lit views to provide the maximum possible size for the active view. But Ifind that clutter of nun-active views an Irrilatiun. even it 648 « 40»
resotut ion.
CED'i Imitation: in display lie In sharp contract to the rest of the
program, which is a model of flexibility. Vou can create, load and save
macros, bound to any key. that customize your own interaction with the
proyran. Vein can create multiple preferences tiles that, in addition Id
screen size, display colors, foul and so en, contain settings for edit
modes, save node, task priority, nacrci neiinitiun*. tabs nnd many other
variables, the screen si;e. by the way. can be increased up to 1BB3 by
command let. Tor example, the CCEOIT environment variable of the Hjm
an specify an ARexx script to be invoked after each
written an ARexx script that positions my CED text
p
conpilation.
npih
:t the error before moving or the next one. Dnce I'n satisfied with
irrBcLlani, I can start the whole cycle alt over again.
/• interactive C editor */
CtDPro review:
Tin Grant ham
CygnusEd Professional 2.11 lets you have up to ten files open at once.
play was mangled in both file display
and requesters. I hope a version com
patible with 2.0 will be out soon.
The spiral-bound manual, by the
way, is excellent. The well-organized,
intelligible prose provides lots of use
ful, accurate advice. While head and
shoulders above its peers, it could still
stand a little improvement. For exam
ple, the tutorial asks the user to begin
typing into the new view, which is im
possible, because the default environ
ment makes the file noneditable. This
is hardly a reassuring start for a nov
ice! I was glad to see an index, but it
needs even more references (Autosave,
for example, has only one page refer
ence, and not to its major appearance).
In summary, CED is a solid program
packed with useful features that will
make any programmer's life easier. For
my money, UEdit provides more fea
tures for the dollar than CED and a
display that's more to my taste. I sus
pect, however, many loyalists and new
converts will feel CED's Undo feature
alone is cheap at twice the price.
CygnusEd Professional Release 2.11
ASDG Inc.
925 Stewart St.
Madison, WI 53713
60£/273-6585
S99.95
No special requirements.
Macro68
Algebra
Two new assemblers with new
syntax, too.
By Jim Butterfield
WITH SO MANY assemblers avail
able—some free, some supplied with
compiler systems, and some sold com
mercially—a new assembler has to
have excellent features to attract no
tice. Macro68 (The Puzzle Factory) is
fast, full-featured, and covers a wide
range of system and chip environ
ments. As such, it's worthy of atten
tion. The other newcomer, Algebra
(Aelen Corp.), does not stand up as
well to scrutiny.
GOOD NEWS FIRST: MACRO68
Macro68 is purely an assembler: It
does not incorporate an editor or a
full-scale linker. Commodore's
MEmacs and The Software Distillery's
BLink are supplied for doing those
jobs. You might prefer another text ed
itor, especially if you want to take ad
vantage of the ARexx interface
provided. No debug program is sup
plied, but the included profiler is use
ful in analyzing the efficiency of your
code. For small or repetitive correc
tions, the supplied utility CHANGE9U
allows "stream editing," If you wish to
bypass the object/linking step and gen
erate executable code directly, assem
bler directive EXEOBJ will let you.
The three-disk package is comple
mented by a 128-page manual and a
large READ.ME file. Tutorial and refer
ence materials are intermixed in both,
which makes for heavy reading if
you're looking for something specific,
such as whether the program installs
on a hard disk fit does). Regrettably,
there is no index. You may need to
read through the documentation more
than once to get a feel for the scope of
this package. Disk 3 contains numer
ous code examples.
Macro68 supports the Amiga's origi- *
The AW Tech fcunial 27
Reviews
rial processor, the 68000, plus its big
brothers: the 68010,68020,68030, and
68040. Good support exists for floating
point chips, the 68881 and 68882, and for
the 68851 MMU; there's even provision
to allow code to be written for the
Amiga copper. The include files that
come with the current version of
Macro68 are 1.3 versions only. Version
2.0 include files will undoubtedly be
made part of the package when Com
modore releases and licenses them.
As the 68000 family has grown, Mo
torola has adopted a new system of
syntax for opcodes and addressing
modes. Prepare for a shock: Your exist
ing program files and assembler will
become partly outdated. Here are a
couple of examples that show the kind
of changes taking place. A favorite
Amiga command, MOVE.L 4,A6, is
now precisely coded as MOVEA.L
(4).w,A6. In this case, the switch from
MOVE to MOVEA and the addition of
.w are not too significant—most as
semblers would optimize these. The
need for parentheses is a radical
change, however, deemed necessary
for uniformity with more complex ad
dressing modes in the newer proces
sors. Consider also the "short branch."
Most programmers traditionally would
write it similar to BRA.S LOOP. The .S
flag for short is now reserved for the
math coprocessor chips. In the new
format, you code BRA.B LOOP using
.B to signal a byte-length branch. Simi
larly, BRA.L becomes BRA.VV, signaling
that the branch is word-sized.
Macro68 does its best to adopt the
new format without threatening the
old. While assembling using the NEW-
SYNTAX option causes the assembler
to insist on the new format, assem
bling with the OLDSYNTAX option
(the default) instructs the assembler to
recognize both the old and new for
mats. Alternatively, you could convert
the old source to the new format via
the NEWSYNTAX utility. A useful pro
gram, NEWSYNTAX runs quickly,
does the job, and produces code with
more detail. I have a tendency to write
code such as TST DO; the conversion
would change this to TST.W DO, re
minding me that the instruction as
written will test 16 bits, not the whole
32-bit DO register.
FAST AND FRIENDLY
Macro68 is as fast as any assembler I've
seen. A test file of 4000 statements, in
cluding 2000 symbols defined and
used, assembled in less than seven sec
onds on my Amiga 2000. That's with
modes OLDSYNTAX and RELAX,
which are said to be the "slower" style
of operation. The opposite modes,
NEWSYNTAX and STRICT, however,
produced the same results. Assembly
time will, of course, be slower when
you specify output files for listings or
cross-references. As to listings, the for
mat of these files is rather ragged and
is not as detailed as I would like, but
it's clear enough for most uses.
As Macro68's name suggests, it han
dles macros well. The existing stand
ards are supported, and the manual
outlines advanced uses in detail. Con
ditional statements and loops are easy
to set up. You can even make preas-
sembled macro libraries resident at as
sembly time, speeding up an already-
fast assembly run.
Macro68 does little optimizing of
code; only the most obvious things are
done. Some assemblers, for example,
change MOVE.L #0,D0 to the appro
priate MOVEQ instruction, or even
discard LEA 0(A4),A4 because it only
wastes time. Not so with Macro68:
What you write is mostly what you
get. For example, backward branches
are made short (byte-sized) if they
reach, and ADD becomes ADDA or
ADDI where appropriate. No subtle
optimizations here.
You can customize Macro68 in many
ways. While a configuration file lets you
change defaults to your favorite set
tings, you can adjust more than assem
bler options. You can define symbols or
even generate startup code if desired. A
custom file, more correctly a customiz
ing file, goes deeper, letting you change
the workings of the assembler itself. For
example, if you do not like or use the
ABCD command, you can remove it
completely from the assembler and save
the lookup time, or you can move it
down the priority list so that this code is
only searched for after everything else
has been checked. Suppose you use
MOVEQ frequently—you can move
this instruction to the top of the lookup
table to gain extra assembly speed.
Macro68 is rich in directives. You
can execute CLI commands during the
assembly process or even send ARexx
messages. You can quickly define
structures by use of the SO (structure
offset) directives, comparable to the RS
directive of some other assemblers.
There's also a "negative SO" directive,
FO, (frame offset) to allow easy stack
frame definitions.
All these new features add up to
make Macro68 a strong contender.
Fast, powerful, and flexible, it's even
up to date with the new Motorola syn
tax. Perhaps this assembler is not as
user-friendly as some requester- and
menu-driven ones, but it gets the job
done quickly.
THE INDIVIDUALIST: ALGEBRA
By contrast, Algebra tries to be too
friendly. An assembler-style program
that produces code for an Amiga or a
single-board computer, Algebra pro
poses a new format for writing 68000
code, quite different from the standard
assembly language. For example, to
add a value of 39 to register D3, you
would use D3 +#39 as opposed to the
conventional assembler coding
ADD.W#39,D3. Similarly, if you want
your program to branch if register D5
contains a value of 10, you would use
emp d5#10 L followed by beq target
rather than the traditional CMP.L
#10,D5 and BEQ TARGET. Make your
own decision as to which is easier. I'm
used to the traditional forms, but AI
DePaul, the originator of Algebra, ob
viously feels that the algebraic method
is more natural.
The Algebra package consists of a sin
gle disk; the manual comes as a data file
on the disk. No include files are pro
vided. If you want to call Exec function
AtlocMem, for example, you must sort
out for yourself that the offset is —216
decimal. Algebra itself is actually two
programs—ALGEBRA, the assembler,
and BLD, the loader. Both were written
in compiled BASIC and run reasonably
quickly for small programs. They are
not, however, in the same league as
professional assemblers.
Algebra converts the original code
into machine language. Not an object
file, not an executable file, but pure
machine language. As such, it won't
load directly into the Amiga. You must
use BLD for each load to make space
for the program. BLD leaves a message
in RAM stating what memory space it
has reserved. Your "main" program
then reads the message, reads the ma
chine language into the reserved
space, and calls it. That's uncomforta-
ble, because the Amiga's built-in
loader automatically finds space for a
properly constructed loadable pro-
Continned on p. 40
22 April/May 1991
° TNTTechnical News and Tools from the Amiga community.
Compiled by Linda Barrett Laflamme
Boost Your Memory PowerIf you can't memorize something, know where to look it
up. To help you, Vidia (PO Box 1180, Manhattan Beach, CA
90266, 213/379-7139) has compiled the Amiga Programmer's
Quick Reference. This 16-page, 81/; x 11-inch book provides
a complete ASCII table (including binary and hex transla
tions), ANSI console control and report codes, Rawkey codes,
compiler and linker flags for Aztec and SAS (formerly Lattice)
C compilers, library names and base addresses, Amiga con
sole control sequences, the console device report stream, and
guru meditation error definitions. Whether you need such
general information as C or 68000 assembly language com
mand explanations and guidelines or specific details, such as
note frequencies or RGB color values, the Quick Reference
is the place to look. Add to that the programming pointers
in the margins and the S7.95 price seems a bargain. Graphics
and desktop publishing guides are also available.
~
~
A System Plus SourceGear up for Unix on the
Amiga with MINIX 1.5
($169). Originally developed
as a teaching tool, MINIX 1.5
is a Unix-like multitasking,
multiuser operating system
from Prentice Hall (College
Technical and Reference Di
vision, Simon & Schuster
Higher Education Group,
Prentice Hall Building, En-
glewood Cliffs, NJ 07632,800/
624-0023, 201/767-5969). Sys
tem-call compatible with
Unix version 7, the package
includes a K&R-compatibleC
compiler, three editors based
on ed, vi, and emacs; a shell
identical to Unix's Bourne
shell, more than 125 urilites
(including cat, grep, li, make,
nroff, sort, and spell), plus
more than 255 library proce
dures (including atoi, fork,
mallock, read, and stdio).
MINIX 1.5 also comes with
the complete C source code
for almost all ultilites and the
operating system. For those
who prefer to read code in
print instead of on the screen,
the 688-page manual lists the
entire operating system's
source code. You will need at
least one megabyte of RAM
to run the nine-disk package,
but a hard drive will do you
no good. They are not sup
ported.
The Rx for ARexxARexx let you combine your compatible programs to pro
duce even more powerful applications. Rx_Tools ($54.95)
goes one step further, pairing with ARexx to let you access
Intuition and add custom graphical user interfaces to your
combined programs. The ARexx and Rx_Tools team gives
you a complete development environment (with a built-in
text editor) with which you can more easily add windows,
requesters, menus, and gadgets to your programs. For more
details contact TTR Development, 1120 Gammon Lane, Mad
ison, WI 53719, 608/277-8071.
Any Way You Like ItTurboText ($99) promises
speed and flexiblity at any
level. You can simply record
macros or use the interactive
ARexx-based development
tools to write, check syntax
of, compile, and test code in
any language. The basic
functions list includes cen
tering, justification, search
and replace, upper/lower
case conversion, and clip
board-based cut and paste.
For advanced features you
can expect an integrated
programmer's calculator, a
hexadecimal editing win
dow, outlining capability,
text template support, key
board and menu remapping,
plus the ability to redefine all
text strings so you can cus
tomize the editor to your fa
vorite language. Old editing
habits can be hard to break,
so TurboText emulates such
Amiga, Unix, and PC editors
as TxEd + , CygnusEd,
MicroEMACS, and QEdit.
Need even more customiza
tion options? Take a look at
the ARexx macro interface
with more than 130 com
mands, auto-case-correc
tion, which automatically
switches letters to which-
The AWTech Journal 23
TNT
ever case you specify, and
auto-word-correction,
which lets you define a dic
tionary the program uses to
automatically correct mis
spellings. The company be
hind the product is Oxxi
Inc.; contact them at 1339 E.
28th St., Long Beach, CA
90806, 213/427-1227.
Toaster ChallengeIf you're one of the many who see the Video Toaster and
say, "What great effects, but / would have programmed it
differently," you're going to get a chance to prove your
words. NewTek is releasing specifications on how to access
the Toaster libraries, as well as a callable ARexx interface to
the libraries. Stay tuned for more details or, for the latest in
formation, contact NewTek directly at 215 E. 8th St., Topeka,
KS 66603, 913/354-1146.
Eyes on the Summer
While still deep in development, Oxxi's Modula II com
piler ($199) is reportedly posting some interesting numbers.
On a stock Amiga, this multipass compiler sped to a rating
of 1500 Drystones, compared to SAS Cs 1100-1200 Drystones
for the same test. Promising to use the IEEE floating-point
library and to handle blocks larger than 32K, Modula II is
scheduled for release in June. Watch for more details.
On Tap
Whether you have a new
product to proudly announce or
some juicy news to whisper,
we've got willing ears. Drop us
a note at TNT, The Amiga-
World Tech Journal, SO Elm
St., Peterborough, NH 03458,
or call 603/924-0W0, ext. 118.
PD ToolboxFancy packaging and splashy
ads don't mean a product is su
perior, especially when you're
comparing technical applications.
Many plain-clothes PD programs
deserve as much mention as their
commercial cousins. Consider
compilers, for example. For your
first foray into a foreign language,
experimenting with a PD compiler
before investing in a commercial
equivalent makes good sense. You
may find you never need to switch.
On BIX alone, you'll find several
choices for compilers, with C pack
ages (such as cc68K_c.arc and
the sozobonc—1.zoo/sosbonc_
2.zoo combination) most common.
Of particular interest are DICE C
version 2.05.07 (dice205c.lzh) from
Matt Dillion and PDC (pdcbin.lzh)
from Lionel Hummel, Paul Peter-
sen, and friends. DICE (Dillon's In
tegrated C Environment) is a
complete C preprocessor, includ
ing a compiler, an assembler, a
linker, and support libraries, plus a
dme editor. For features you can
expect ANSI compatibility, plenty of
code optimizations, autoinit rou
tines, and more. You will, however,
need includes/amigaJib from Com
modore. Housed in three files
(pdcbin.lzh, pdclsrc2.lzh, and
pdcsrc.lzh), the PDC package in
cludes a compiler, an assembler, a
linker, and a librarian, as well as
several utilities, documentation
files, libraries, and header files.
PDC supports such features as all
ANSI preprocessor directives, func
tion prototyping, and structure
passing and assignment, pius it
also supports SAS C compatible
libcall pragmas, precompiled
header files, built-in functions, and
stack checking codes. If you really
want to dig into the system's guts,
you can study all the source code,
which is kindly provided.
Speak with a forked tongue?
Check out DevKit (devkit.zoo) by
Peter Cherna. A combination of C
and ARexx language programs,
DevKit lets you launch your com
piler from within your editor, auto
matically position the cursor on
errors, press one key to took up
the autodoc page for any Amiga
function, find a system structure or
define within the include files, or
find any function in the your source
code. You can also put the com
piler options in the source code in
a supplied utility for quick reference
and modification.
More exotic languages are also
available. Version 1.2 of the
DRACO compiler (draco_v12.
zoo.) is a hybrid of Pascal and C
by Chris Gray designed to create
fast and compact object code. It
can access the majority of the op
erating system's features; see the
file DRACO_DOCS.ZOO for more
details. If you prefer a straight Pas
cal compiler, check out pascal.lzh.
Finally, the Oberon (oberon.lzh) is
an object-oriented language devel
oped by Prof. Dr. Niklaus Wirth of
ETH Zuerich in Switzerland as a suc
cessor to Modula-2. A single-pass
compiler, this version creates stand
ard Amiga object files, uses a mul
titude of optimizations, supports
writing of re-entrant programs, and
lets you call code from other lan
guages. The package includes a
compiler, an editor, a linker, a pro
gram to display compilation errors,
as well as demos. You can thank au
thor Fridtjof Siebert for this version.
The PD is no slouch on utilities,
either. Four worth looking at are
KickDate, ParNet, RexxHostLib,
and SetCPU, found on Fred Fish
disks 408, 400, 403, and 400, re
spectively. KickDate saves and re
trieves the system's current date
stamp to and from the first sector
of the Kickstart disk. A1000 owners
with autobooting hard drives will
appreciate this program, as it
saves the system time through re
boots and power downs. All pro
grammers will appreciate the
source code that author Joe
Porkka provides. With a special
DB25 cable and ParNet (parnet2.
Izh on BIX), you can connect two
Amigas via their parallel ports, and
one can mount the other as a de
vice, reading and writing its files
as if they were local. This version
2.4 is the Software Distillery's NET;
file system that uses Matt Dillon's
parallel port code. Written by Olaf
Barthel, RexxHostLib version 36.14
(rxholi.lzh in CompuServe's
AmigaTech Programmers Utilities
library) is a shared library package
that helps you create and manage
ARexx hosts. So that you can con
trol ARexx from programs in Amiga
Basic and such, the package in
cludes Rexx-message parsing.
Yes. Olaf also provides source. An
update of an old favorite, SetCPU
version 1.6 (setcpu.lzh on BIX) lets
you detect and modify parameters
related to 32-bit CPUs with com
mands that enable and disable
text/data caches, switch on and off
the 68030 burst-cache line-fill re
quest, use the MMU to run a ROM
image from 32-bit memory, report
parameters when called from a
script, and more. Commodore en
gineer Dave Haynie even provides
his source code.
24 April/Mm/1991
The AmigaWorld
Tech Journal
Disk
'
~
This nonbootable disk is divided into two main directories,
Articles and Applications. Articles is organized into subdirec
tories containing source and executable for all routines and
programs discussed in this issue's articles. Rather than con
dense article titles into cryptic icon names, we named the
subdirectories after their associated authors. So, if you want
the listing for "101 Methods of Bubble Sorting in BASIC," by
Chuck Nicholas, just look for Nicholas not 101MOBSIB. The
remainder of the disk, Applications, is composed of direc
tories containing various programs we thought you'd find
helpful. Keep your copies of Arc, Lharc, and Zoo handy;
space constraints may have forced us to compress a few files.
All the supplied files are freely distributable—copy them,
give them to friends, take them to the office, alter the source
if it's provided. Do not, however, resell them. Do be polite
and appreciative: Send the authors shareware contributions
if they request it and you like their programs.
Before you rush to your Amiga and pop your disk in, make
a copy and store the original in a safe place. Listings provided
on-disk are a boon until the disk gets corrupted. Please take
a minute now to save yourself hours of frustration later.
If your disk is defective, return it to AmigaWorld Tech Jour
nal Disk, Special Products, 80 Elm St., Peterborough, NH
03458 for a replacement.
The AW Tech journal 25
Probing Your System's
Current AmigaDOS Device ListFollow these pointers and structures to a system-wide
list of active devices.
By Eugene Mortimore
ONE OF THE FEATURES that make the Amiga so pow
erful is its ability to maintain vital system-wide information
on precisely-current linked lists. This theme runs throughout
al! Exec operating subsystems and is central to a complete
understanding of this complex software system.
The Exec software system accomplishes its principal book
keeping chores by continuously updating parameters in its
ExecBase structure and that structure's List substructures.
For instance, if a user launches a new program and that pro
gram then subsequently adds a new library to the system,
the Exec system will recognize that event and automatically
update the ExecBase structure library list placing the new
library on the list.
At any time, from initial system creation forward, the Exec
system software automatically assures that this summary
data always represents a capsulized current-system-state
snapshot. Then, by reading appropriate structure parame
ters, you can always probe this snapshot to determine which
software resources are in the system at that time. Through
this probing, each program can determine which Exec soft
ware resources are available to it at each point of execution
and, as necessary, add any required software resources that
are not already present. The hidden Exec internal routines
allow you to ascertain crucial information whenever your
program needs it.
The ExecBase structure and its List substructures allow
programmers to probe into current lists for Exec libraries,
Exec memory blocks, Exec software interrupts, and so on.
The Exec system also maintains a list of Exec devices; typi
cally a program would find the serial.device and the paral
lel.device and others on this list. These are device names in
the Exec device name space.
The AmigaDOS system deals in a different device name
space. Here, for example, 5ER: is the name of the serial device
and PAR: is the name of the parallel device. Both of these
AmigaDOS devices use the underlying Exec device; any ref
erence to the SER: or PAR: device will always result in execu
tion of the Exec serial or parallel device routine, respectively.
Therefore, the system has a set of shorter-named AmigaDOS
devices. It is then natural to ask the following questions:
• Does the AmigaDOS system have a device-related list-based
software-resource bookkeeping mechanism similar to Exec's
system?
• If so, how and when does the system update its AmigaDOS
device list?
• How can a programmer work through the AmigaDOS de
vice list to determine which AmigaDOS devices are currently
in a specific system?
26 April/May 1991
• Finally, how can a programmer use the AmigaDOS device
list to advantage?
TYPES OF AMIGADOS SOFTWARE DEVICES
The AmigaDOS system deals in AmigaDOS software de
vices. By system convention, all AmigaDOS devices are al
ways assigned to one of three device categories: real devices
(related to actual physical devices), logical assigned director}/
devices and disk volume devices. The dos.h include file con
tains three C#define statements that name these categories
as DLT^DEVICE, DLT_DIRECTORY, and DLT_VOLUME,
respectively. (As an important aside, you should know the
relationship—and distinction between—AmigaDOS devices
and Amiga processes. Each AmigaDOS software device is al
ways associated with one-or-more Amiga processes, each pro
cess being defined by its own AmigaDOS process structure.
Thus while there may indeed be more than one active serial
device process in the system at any one time, there is still only
one AmigaDOS SER: software device. Its executable code is
used by all of those serial device processes.)
Just as for Exec above, the AmigaDOS system maintains
these AmigaDOS devices as separate device nodes on a
system-wide list a program can examine at any time. By ex
amining the current list, the program can determine in detail
how a machine's hardware system is currently configured—
which real physical devices are currently mounted, which
logical directory devices are currently assigned, and which
disk volumes are currently in the system's disk drives.
For example, if your program needs to determine if the
hardware system has a third floppy drive associated with a
mounted AmigaDOS DF2: software device—perhaps an
MS-DOS 5V;-inch drive—it can examine the current Amiga-
DOS device list for a DF2: device. Once DF2: is confirmed to
be mounted, and therefore present on the AmigaDOS device
list, additional program statements can then examine the de
vice characteristics of DF2: to determine if it is a MS-DOS
5:/:-inch disk-drive device.
Similarly, the same list-searching procedure will allow
your program to determine if the logical libs: and devs: (or
other) directories have indeed been properly assigned and
to determine if a specific disk volume is indeed currently pre
sent in a specific disk drive.
Disk volume verification is required because many com
plex multifloppy programs expect a specific disk volume
(with a specific volume name) to be inserted in a drive before
they can continue. Now, if that disk volume is indeed in the
proper drive, the AmigaDOS system will have already au
tomatically placed it on the current AmigaDOS device list. If
~
~
the disk is not in the proper drive, it will not be on the current
AmigaDOS device list. The program can then alert the user
to insert it in the proper drive.
REAL DEVICES
Table 1.0 summarizes some of the most common real
AmigaDOS software devices. You can see that these devices
are always related to physical hardware—hence the adjec
tive real. Note that some of these (software) devices talk di
rectly to the underlying Exec (software) device while some
use an intermediate file call a handler file that is always in the
system's L: directory; this handler file then talks directly to
the underlying Exec (software) device. Some of these (soft
ware) devices are automatically mounted by the system
Figure 1. Relationship
between bookkeeping structures
in the AmigaDOS
system software.
DosLlbrary Structure
dl_Root
T
RootNode Structure
Rn_lnfo
T
Doslnfo Structure
dr_Devlnto
▼
Devlnfo Structure (1st device)
dvr_Next
T
Devtnto Structure (2nd device)
dvr_Next
T
dvr_Next
T
Devlnfo Structure (Nth device)
while others may require explicit devs: directory MountList
file entries and related MOUNT commands.
In a minimally configured system you will typically find
the following real AmigaDOS devices: DFO:, DF1:, SER:,
PAR:, PRT:, RAW:, CON:, and RAM:. A more advanced hard-
drive system perhaps configured for engineering purposes
might have HDO: and HD1: devices and perhaps LPEN:
(light pen) or JSTK: (joystick) devices. HDO:, HDI:, LPEN:,
Table 1.0: A Partial List of Real (Physical) Devices
In Many Amiga Systems
Device
Name
Description
~
Real Physical Devices that Use ROM-based or DEVS: Directory Exec Device Files
DFO: Disk In DFO: (Floppy Disk 0): Disk type "DOS", "KICK":
DF1: Disk In DF1: (Floppy Disk 1): Disk type "DOS", "KICK":
DF2: Disk In DF2: (Floppy Disk 2): Disk type "DOS", "KICK":
DF3: Disk in DF3: (Floppy Disk 3): Disk type 'DOS1'. "KICK":
FFS: Fast File System: (Hard Disk): Disk type "DOS", "KICK":
FAST: Fast File System: (Hard Disk): Disk type "DOS", "KICK":
DHO: Disk Partition DHO: (Hard Disk 0): Disk type "DOS", "KICK":
DH1: Disk Partition DH1: (Hard Disk 1): Disk type "DOS", "KICK":
RAD: Recoverable RAM Disk RAM: Disk: Disk type "DOS", "KICK":
Real Physical Devices that Use L: Directory Handler Files
SER: Buffered serial device: Uses
AUX: Unbuffered serial device: Uses
PAR: Buffered parallel device: Uses
PRT: Printer device: Uses
PIPE: Input-output intraprogram communication: Uses
SPEAK: Speech output: Uses
CON: Cooked keystroke console device: Uses
RAW: Raw keystroke console device: Uses
NEWCON: Enhanced replacement for CON: Uses
RAM: Nonrecoverable RAM: disk: Type ■DOS", "KICK": Uses
Uses Exec "trackdisk.device1
Uses Exec "trackdisk-device'
Uses Exec 'Irackdlsk.device'
Uses Exec "trackdlsk.device"
Uses Exec "hddisk.device"
Uses Exec "hddisk.device"
Uses Exec "hddisk.device"
Uses Exec "hddisk.device"
Uses "ramdrive.devlce"
Port-Handler handler file in L directory
Aux-Handler handler file In L directory
Port-Handler handler file in L directory
Port-Handler handler file in L directory
Pipe-Handler handler file In L directory
Speak-Handler handler file in L directory
ConHandler handler file In L directory
ConHandler handler file in L directory
Newcon-Handler handler file in L directory
Ram-Handler handler file In L directory
The AW Tech Journal 17
Amiga Device List
and JSTK: entries would appear in that system's MountList
file, and associated MOUNT commands would actually place
these devices on the AmigaDOS system device list.
Going further, if you were so clever as to design the hard
ware for Carnegie Mellon's video harp, you would first cre
ate an Exec (software) videoharp.device to talk directly to
your new video harp hardware and then create an 1: direc
tory-based VideoHarp-Handler (or whatever you wished to
call it) file to talk to the underlying Exec videoharp.device.
You would then place a VHRP: entry—with appropriate pa
rameters describing the input-output characteristics of a
video harp—in your devs: directory MountList file and issue
a MOUNT VHRP: command. The MOUNT command would
then place the VHRP: device on the AmigaDOS device list
for any program to recognize and use as needed. That pro
gram would then be able to converse with the video harp.
The presence of any of these devices on the AmigaDOS
device list implies the concurrent presence of hardware and
controlling device software—the AmigaDOS device soft
ware—in the system. Generally speaking, then, real Amiga-
DOS devices represent software systems that allow process-
information transfer back and forth between actual hardware
dances and some other parts of the machine, most often, but
not necessarily, RAM.
LOGICAL DIRECTORY DEVICES
The second type of AmigaDOS device present in all sys
tems is the logical directory device. A typical system will in
clude the following logical directory devices: SYS:, ENV:,
DEVS:, LIBS:, FONTS:, S:, L:, and C:. Some of these devices
are created by the system at bootup—for example, by hidden
L:, C, LIBS:, and DEVS: system assigns. Others are created
when an ASSIGN command is directly executed.
For example, if your startup-sequence file contains many
logical assigns, the system will automatically recognize these
and create a separate AmigaDOS software device for each
one you specify. Also, if a user explicitly enters an ASSIGN
statement, the system will recognize that event and create a
new logical directory device for it. If a program issues an
EXECUTE("ASSIGN namel name2") function call, the
AmigaDOS system will place a logical directory device for
namel on the AmigaDOS device list.
DISK VOLUME DEVICES
The third type of AmigaDOS device is the disk volume de
vice. In any system, each distinct physical disk will have a vol
ume identifier assigned to that specific disk volume. This label
is usually placed on the disk by the user with the RELABEL
command. The AmigaDOS system will automatically recog
nize these volume names and create a software device for each
one, giving that device node the name of that volume.
BOOKKEEPING AMIGADOS STRUCTURES
Table 2.0 briefly describes the four structures—DosLibrary,
RootNode, Doslnfo (defined in the dosextens.h include file),
and Devlnfo (defined in the dos.h include file)—that the
AmigaDOS software system uses to maintain its AmigaDOS
device list bookkeeping. Figure 1.0 shows how specific in
stances of these four structures are linked together to allow
your program to examine the current AmigaDOS device list.
Let's take a look at the structure features that allow you to
examine the most important AmigaDOS device names on
the current AmigaDOS device software list.
The DosLibrary structure consists of an Exec Library
(substructure with appended information specific to the
AmigaDOS system:
struct DosLibrary {
struct Library dLJIb;
APTR dLRoot;
APTR dl_GV;
LONG dl_A2;
LONG dl_A5
LONG dl_A6;
}:
Your program can obtain a pointer to a DosLibrary structure
instance as follows:
struct DosLibrary *dosLibrary-NULL;
dosLlbrary = (struct DosLibrary •) OpenUbrary(DOSLIBRARYNAME, OL);
Here dLRoot points to a specific RootNode structure \^,
instance.
The RootNode structure holds vital system-wide infor
mation about the DOS software system.
struct RootNode {
BPTR rn_TaskArray;
BPTR rn_ConsoleSegment;
struct DateStamp rn_Time;
LONG rn_RestartSeg;
BPTR rn_lnfo;
BPTR rn_RleHandlerSegment;
};
Your program can obtain a pointer to a RootNode structure
instance as follows:
struct RootNode *rootNode = NULL;
rootNode = {struct RootNode •) dosLlbrary->dl_Root;
The rn—TaskArray parameter maintains a current list of all
active CLI processes, while the rn_ConsoleSegment param-
Table 2.0: A Summary of DOS Device Bookkeeping Structures:
Description and Purpose
Structure Name Description and Purpose of Structure
DosLibrary (1) Exec library structure with appended DOS-specific data
RootNode Defines system-wide information for all currently active CLI processes, disk-validator and file-handler processes
Doslnfo Defines Amiga computer network behavior and contains a pointer to a Devlnfo structure
Devlnfo Defines a linked list for real, logical directory, and disk volume AmigaDOS devices
28Aprii/Mm/ 1991
Amiga Device List
~
~
eter allows programs to probe into the details of all currently
active CLI processes. Each CLI process will use the CON:,
RAW:, or NEWCON: real device to define its executable code.
The rn_RestartSeg and rn_FileHandleSegment parameters
let you probe into the details of the generic (only one code
copy used) disk validator process and the generic file handler
process. Here rn_Info points to a specific system-initialized
Doslnfo structure instance.
The Doslnfo structure helps define Amiga operations in a
computer network. Its di_Dev!nfo parameter contains a
pointer to the first Devlnfo structure instance in the always
current full system-wide device list.
struct Doslnfo {
BPTR dLMcName;
BPTR di_Devlnfo;
BPTR dLDevlces;
BPTR dLHandlers;
BPTR dLNextEntry;
LONG di_UseCount;
BPTR dLSegPtr;
BPTR di_SegName;
}•
Your program can obtain a pointer to a Doslnfo structure
instance as follows:
struct Doslnfo 'doslnfo = NULL;
doslnfo = (struct Doslnfo *) BADDR(rootnode->rn_ln!o);
Here BADDR is a dos.h include file macro that converts
BCPL-language BPTR pointers to C-language pointers. The
di_Devinfo pointer points to the first system-initialized
Devlnfo structure instance.
The Devlnfo structure defines a linked list of C nodes for
all three types of DOS devices. Each specific linked list struc
ture instance represents one of these items in the current sys
tem. The system recognizes any device-creation events and
continuously rearranges this list when such events occur. To
show you how you can use this to advantage, the program
below examines and prints key information about each de
vice in your current system.
The definition of the Devlnfo structure is:
struct Devlnfo {
BPTR dvLNext;
LONG dvl_Type;
APTR dvLTask;
BPTR dvLLock;
BSTR dvLHandler;
LONG dvLStackSize;
LONG dvLPriority;
LONG dvLStartup;
BPTR dvi_SegLlst;
BPTR dvLGIobVec;
BSTR dvi_Name;
>;
Your program can obtain a pointer to the first system-
initialized Devlnfo structure instance as follows:
struct Devlnfo "devlnfo = NULL;
devlnio = (struct Devlnfo *) BADDR{doslnfo- >di_Devlnfo);
Your program can access deeper entries in the DOS device
list using the system-maintained dvi Next parameter as il
lustrated in the program below.
The Devlnfo structure parameters pertinent to this dis
cussion are:
dvLNext a pointer to the next Devlnfo structure in
stance in the list; NULL if this is the last device on the current
DOS device list.
dvLType the specific type of device represented by this
Devlnfo structure instance: dvi_Type = DLT_DEVICE (0) for
a real device; dvLType = DLT_DEVICE (1) for a logical di
rectory device; dvLType = DLT_DEVICE (2) for a disk vol
ume device.
dvLHandler a pointer to the filename of a file that rep
resents the handler for this AmigaDOS device. For example,
for the real RAM device, this pointer will point to the name
RAM-Handler, a file in the L: directory. (See Table 1.0.)
dvLName a pointer to the AmigaDOS device name of
the device represented by this Devlnfo structure instance.
For example, the BCPL language BSTR representation of the
string DFO:.
THEORY INTO PRACTICE
You can use the program in Listing. 1 (in the accompanying
disk's Mortimore directory) to generate a full current DOS
system device list. You will notice that, apart from format, its
output is very similar to the ASSIGN command's. You can
therefore infer that the ASSIGN command examines the
DOS device list in much the same way as Listing.l. To gain
an understanding of the general type, context, and meaning
of the program's output, execute the ASSIGN command in a
CLI window and study its output before you run Listing.l
(which was compiled and linked with Manx 3.6a).
The program first opens the DOS (and ARP) libraries and
then accesses all of the AmigaDOS device nodes in the cur
rent system list. It uses the ARP library BtoCStr function to
convert BSTR strings to C strings. You must place the
arp.library file in your libs: directory. You must also place the
ARP library include files—arpbase.h and arpfunc.h—in your
system's include directory. If the arp.library file is not present
in the libs: directory, an Exec alert will appear on the screen.
On the other hand, a failure to open the dos.library will cause
the program to exit after first printing a message explaining
the reason for failure. These two methods of reporting Open-
Libraryf } call errors illustrate two ways to alert the user to
such problems.
The exact current contents of the DOS device list are de
fined by at least six different sources: DOS devices automat
ically mounted or assigned by the system at bootup; the
current contents of your devs: directory MountList file and
corresponding MOUNT commands to mount the devices in
the MountList file; ASSIGN or MOUNT commands in your
startup-sequence script file; explicit ASSIGN or MOUNT
commands entered by a user in a CLI window; explicit AS
SIGN or MOUNT commands executed by an Execute func
tion call in a previously executed program in your system
(since bootup); and disk volumes currently present in your
system.
Typically, the system will always automatically create and
mount DFO:, DF1:, CON:, RAW:, SER:, PAR:, and PRT: devices
and perhaps several others at bootup. Also, the system will al
ways automatically create several logical directories at bootup,
including the C:, L:, devs:, and libs: directories. In addition, the
startup-sequence file may, for instance, explicitly mount a
Continued on p. 46
The AW Tech Journal 29
Shared Libraries for the LazyWant to build a library, but intimidated by
the bookkeeping? Try LibTool.
By Jim Fiore
AN INTEGRAL PART of the operating system, shared li
braries arc collections of routines that all applications in the
multitasking environment can use. Using existing libraries
has always been easy, but building your own was a chal
lenge. After many attempts, 1 have found a simple creation
method. It does not require a lot of maintenance, and you
can use it with a variety of languages, including assembly
and C (both Manx and SAS, formerly Lattice). All you must
create (and ever modify in the future) are the core functions
and a function description file (sometimes referred to as an
id file).
The example in the accompanying disk's Fiore directory
turns a set of ordinary C functions into a shared library using
the Manx C compiler, but you could use the SAS or assembly
language instead.
A STROLL THROUGH THE STRUCTS
To better understand the program's workings, you should
be familiar with a shared library's structure. Libraries are com
prised of four main parts: a Library Node, a function jump ta
ble (often referred to as a vector table), the set of functions, and
the global data for the library. In memory, a library looks sim
ilar to Figure 1. The definition of a Library structure is:
struct Library {
struct Node llb_Node;
UBYTE lib_Flags;
UBYTE lib_pad;
UWOBD lib_NegSize;
UWORD lib_PosSlze;
UWORD lib_Version;
UWORD lib Revision;
APTR lib_ldStrlng;
ULONG lib_Sum;
UWORD Hb-OpenCnt;
K
The Exec keeps track of the library's status via the Flags
field. The NegSize and PosSize fields hold the size (in bytes)
of the library on either side of the library base. The Version
and Revision fields indicate future changes and updates to
the library, The IdString is a pointer to a null-terminated AS
CII string that gives more information about the library. Exec
uses Sum, the library checksum, to ensure library integrity.
The OpenCnt field contains the number of tasks that have
opened the library so far. Each time a task calls Open-
Library( ) for this library, the library increments OpenCnt.
Every time a program calls the complementary Close-
Library( ) function, the field is decremented. If the OpenCnt
30 April/May 1991
equals zero, Exec may remove the library to free more RAM.
A library's vector table is comprised of several six-byte en
tries, one for each function in the library. Each entry consists
of a jump instruction (two bytes) followed by the absolute
address of the function being called. Each function call then,
is a multiple of six bytes behind the library base. For example,
the seventh function in the table would be at location
LibraryBase —42. These six-byte multiples are known as Li
brary Vector Offsets or LVOs, for short.
In addition to the normal application functions, all shared
libraries must have four mandatory functions—Open( ),
Close(), Expunge( ), andReserved( ). Consequently, the first
application function is always the fifth function in the list, at
position 30 (referred to as the Bias, in a id file). The Open( )
and Close( ) functions are called for each OpenLibrary() and
CloseLibrary( ) call. The Expunge( ) routine is used for final
cleanup when OpenCnt equals zero and Exec has decided
to remove the library. The Reserved( ) function is for future
use. Presently, it should return a value of 0 only.
To properly load a library, Exec needs a Resident structure,
commonly called a RomTag. In assembly, a RomTag looks
something like this:
RomTag:
dc.w$4AFC ;the RomTag Identifier.
dc.lendRom
dc.bNO_AUTO_INIT ;Auto-initialize? In this case, no.
dcbVERSlON ;Library version, as used in OpenUbrary().
dc.bNT_LIBRARY ;Type. This Is a Library.
dc.bPRIORITY ;Not used.
dc.lLib_Name ;Pointer to Name string.
dcJLtb Id ;Pointer to ID string.
dc.lLib—Startup ;Poinler to initialization routine.
endRom
Normally, you set PRIORITY to 0. NT_LIBRARY is defined as
9, and the example program uses a nonauto-initialized library
(NO^\UTO_JN1T = 0) to save space and reduce load time.
The only hitch is that the RomTag must be in the first hunk of
the file. If your development system will not allow this (for
example, it requires code to be the first hunk and you cannot
intermix code and data sections), you cannot make shared li
braries. Versions 3.6 and earlier of the Manx C compiler suf
fered from this limitation, but version 5.0 does not.
When designing the library functions' code, you should
keep a few rules in mind. First, the code should be re-entrant,
meaning it does not use global variables. All variables should
be held on the stack or allocated as needed, because several
Functions
■| Vector Table
Library structure
Library data
The Library Base address
Figure 1. A typical library's structure In memory.
tasks can open and use the library simultaneously. If two
tasks call the same function at about the same time, one task
could alter a global variable before the other task is finished
with it. The results would be chaotic at best. In contrast, you
can use such global constants as fixed strings and look-up
tables (for example, a sine wave table). Because constants are
not altered by a function, tasks cannot step on each other.
The second rule to remember is that if your library uses func
tions contained in other libraries, you must open and close
these auxiliary libraries from within your library. For ex
ample, you could create a DrawBox( ) function based on the
system functions Move( ) and Draw( }. Because these two
functions reside in the graphics library, you must open
graphics.Hbrary when you initialize your library and close it
as part of your library's Expunge( ) routine. Finally, do not
use printf( ) style functions from within the library; it will not
have access to stdin, stdout, or stderr. To get around this, the
library functions should return error codes the calling pro
gram can interpret.
LET THE TOOL DO THE WORK
To build a library from scratch, you must create create,
compile, assemble, and link the RomTag, the Library struc
ture, the function table, the initialization routine, the
Open( ), Close( ), and Expunge{ ) routines; and, of course,
the core functions. While you can reuse some elements from
library to library, you must still do a reasonable amount of
setup work each time. To circumvent this, try the LibTool util
ity (in the accompanying disk's Fiore directory). Designed by
Jeff Glatt of dissidents, LibTool creates all of the auxiliary
items you need for a library (including pragmas and header
files) from a single id file that you supply. Using LibTool, you
need to make only two files to create a library: the functions
of interest and the id file.
As an example, I am going to make a library that imple
ments rectangular to polar and polar to rectangular conver
sions. The library will consist of four functions: Mag( ), which
accepts the real and imaginary rectangular components and
returns the polar vector's magnitude; Ang( ), which calcu
lates the vector's angle in degrees from the rectangular com
ponents; Real( ), which converts the polar magnitude and
angle in degrees to the real rectangular component; and
Imaj(), which transforms the same polar arguments into the
imaginary rectangular component. (See AWIib.c in the Fiore
directory.)
These functions require the use of floating-point math. For
the sake of expediency, 1 am using Motorola fast floating
point, so I must open mathffp.library and mathtrans.library
during initialization and close them as part of the clean up.
In addition to the four conversion functions, AWIib.c con
tains mylnit() and mvFree( ). The initialization routine calls
mylnit( ), which opens the required math libraries and re
turns a BOOL value (TRUE or FALSE). If it cannot open the
libraries, mylnit( ) returns FALSE, which prevents my library
from loading. Called by the Expunge( ) routine, myFree( )
closes the libraries that were initially opened. To use the
mathieee libraries, my example library would have to open
each mathieee library for each application that calls it. (Each
task that uses mathieee libraries must open them itself thanks
to the mathieee code that saves and restores the MPU context
on task switches.)
Much of the drudgery is taken care of by LibTool, in con
junction with a specialized function description file. LibTool
creates a library startup module containing the RomTag, the
Library structure, the function table, the four mandatory func
tions, wedges into the various routines (the references to
mylnit( ) and myFree( )), the proper version and revision
numbers, strings, and so on. Also, this module will automati
cally open Exec, the dos.library, in tuition, library, and graphics,
library, because they are used so often {and are most likely al
ready present in the system). If your library needs routines
from these system libraries only, therefore, chances are that
you will not need init and free routines. To aid in the construc
tion of the applications that call your new library, LibTool also
creates a header file, pragma statements, and C "glue" rou
tines. The glue routines pull C arguments off the stack and
place them in the proper registers for the library. LibTool can
create libraries that expect arguments on the stack, as well. The
resulting glue is smaller for C applications, but this does make
it harder to access the library from other languages. Of course,
you can bypass the whole issue of glue routines and use prag
mas. By using pragmas, the C compiler moves the arguments
into the registers and and needs no glue.
The id file is an adaption of the Commodore-standard id
files with which you are probably familiar. LibTool recog
nizes extra commands that allow it to create the complete
library startup module. The example's id file follows:
////base AWBase *the name of our base
■used by C glue code and C PRAGMAS
##name AW *the name of our library (ie, aw.library)
#£vers 1 "version #
0 "revision #
it mylnlt *to be called once (upon loading the lib)
xpu myFree *to be called once (upon expunging the lib)
Continued on p. 47
The AW Tech journal 31
The Fast Floppy SystemWith ROM support for the FastFileSystem,
you can figure on faster floppies.
By Betty Clay
IN THE BEGINNING, the Amiga had one filing system.
The original AmigaDOS filing system is slow and cumber
some at times, but it has one great virtue—it allows you to
recover almost anything lost on a disk. Every sector on the
disks it formats contains a great deal of information to aid in
file recovery.
As the file system matured, fewer disks failed and users
clamored for faster drives. The result of Commodore's effort
to meet this need is the FastFileSystem, or FFS. It was released
two years ago, but was recommended for use with hard disks
only—not floppies. The Amiga's ROM did not support it, and
for that reason it was neither safer nor even much faster for
use with floppies than was the old system.
Amiga OS 2.0 provides ROM support for both systems, so
we can now safely use the FFS for floppies. To make wise
decisions about using the new system, however, we need to
study it. The differences, while not so great as to affect com
patibility with disks we already have, are quite significant.
REGARDEZ LA DIFFERENCE!
To compare the two file systems fairly, I formatted one disk
under each (using the 2.0 FORMAT command), and then
copied the same information (Workbench 2.0 beta) to both
disks. All the while, I observed their differences. I learned
immediately that 2.0 can recognize a disk formatted under
either system, while 1.3 is unable to validate FFS-formatted
disks. For this reason, people who distribute disks widely will
most likely continue to use the old file-system disks.
AmigaDOS 2.0 defaults to the old file system, and you must
add FFS to the startup-sequence's FORMAT command in or
der to format with the new system.
As a disk fills with data, the filing system creates several
different kinds of blocks, or sectors. On current Amiga disks,
each 512-byte block is divided into 128 longwords, called
slots. There are various types of blocks (including boot
blocks, directory blocks, file-header blocks, extension blocks,
file-list blocks, and data blocks), some of which are not af
fected at all by the FastFileSystem. Let's take a look at those
that are affected.
The first two blocks at the beginning of every hard or
floppy disk are called the boot blocks, and the initial long-
word holds a number that indicates which filing system that
disk uses. The old file system's number is 1146049280 in dec
imal form and 444F5300 in hexadecimal form. The ASCII
translation of S444F5300 is: $44 = D; $4F = O; S53 = S, and
00 = 0, for a result of DOS 0. Under the FastFileSystem, the
numbers are 1146049281 decimal and 444F5301 hexadecimal,
which translates to DOS 1.
32 April/May 1991
The first thing the Amiga does is read the number in the
first position on the disk. If the system does not recognize
that number, the message "Not a DOS disk in dfn:" appears.
If that number is corrupted on an otherwise valid Amiga
disk, you may be able to rescue the disk by using a disk editor:
Check the first longword, correct it if it is corrupt, and then
correct the checksum before rewriting the sector to the disk.
DIRECTORY BLOCKS
After checking the boot block, the system moves to the root
directory, which is the heart of the disk- The root directory
is located in the center disk sector—sector 880 of a normal
Amiga floppy disk. This sector begins with six slots of system
information, followed by 72 slots of 32 bits each (occupying
positions 6 through 77) that hold location data for user di
rectories, icon files, file-header blocks, and so on. These 72
slots are called the keys, or pointers, to the files.
The restriction of 72 slots is not a system limitation; it is the
current block size of 512 bytes that limits each directory block
to 11 entries. The Amiga's software allows you to use blocks of
other lengths, and through a system called hashing, you can
enter more than 72 filenames in a directory. (Perhaps it is for
this reason that the 72 slots are known as the hash table.)
Beginning with slot 78 there is a 32-bit word that holds the
bitmap flags. This slot contains a 0 on an unvalidated disk
and a —1 on a validated disk. If you insert an unvalidated
disk (a disk that contains a 0 in this position) into your drive,
the validator will automatically begin to read every byte on
the disk and will rebuild your bitmap before placing a — 1 in
this slot. You cannot write to the disk (hard or floppy) until
the validation process is complete—which can take quite a
while, especially on a large hard disk filled with data.
Be sure to wait for a few seconds after the drive light goes
out before removing a disk from the drive. Often, the light
goes out initially because a file has finished writing, but then
comes on again while the system updates the bitmap and sets
the bitmap flag. Should you remove the disk before the bit
map flag is set, your disk will not be validated. The disk val
idator may be able to help you recover such a disk if you
change the bitmap flag to 0 (unvalidated) using a disk editor.
The next 25 positions, numbers 79 through 103, are filled
mostly with zeros on floppy disks, but it is here that a minor
difference between the old and new file systems becomes
apparent. The new system puts the first BitMapKey in po
sition 103, the next in 102, and so on, and puts the Bit-
MapExtension number (where applicable) in slot 79. The old
system puts the BitMapExtension in position 103 and begins
the BitMapKeys in position 102. On a floppy disk, there is no
need for more than one block of BitMapKeys, and there will
never be a BitMapExtension number. Each position in the
bitmap holds a 32-bit number, which signals whether 32
blocks are empty or filled, so a bitmap block can hold the data
for 4064 sectors. Because an Amiga floppy has only 1760 sec
tors, one bitmap block is enough for any floppy—and even
the new high-density disks do not have enough blocks to
require more than one block for the bitmap. (This is not true,
of course, for large hard disks.)
The bitmap block does not always remain in the same
place on the disk. Its location is stored in position 79 of the
root block, and on each of the disks I studied for this article,
the bitmap was placed on sector 881—adjacent to the root
directory itself. Each time you alter the disk, the new bitmap
is written to a different place (the old one is not erased until
the new one is safely stored). Its location data is then written
into root-block slot 79. The remainder of the root block is un
changed between the two systems.
HEAD OF THE DISK
Although the FFS places icons nearer the center of the disk
than the old system does, both systems read and use icons
in exactly the same manner. The user directories and the file-
header block {the first block of a file) are identical on both
systems. The file-header block holds information that the
system needs for file recovery, checksum, and so on, as well
as the numbers of the sectors on which your file is stored.
The first block your file uses is in position 77 of the file-header
block, the second block is in position 76, and so on up to
position 6—if the file is that long. Should it be longer, the file-
header block will contain the number of an extension block
that holds the numbers of the next group of sectors used by
your file.
While the file-header blocks are identical in the two sys
tems, the file-data blocks are very different. To demonstrate
this difference, I have used a part of the D1R command from
the C: directory. The commands are the same, copied from
the same disk. Here are the beginnings of those blocks:
Old System
0: 00000008
1: 0000005C
2: 000O0001
3: 000001E8
4: 0000005E
5: F4112B7B
6: 000003F3
FFS
0: 000003F3
Explanation
Kind of block (data)
Number of this sector ($5C=93)
How far into tile? First block
Bytes of data per block
($1EB = 488)
Next block in this file (5E = 95)
Checksum
(hunk_header, which loads and
(hunk-code, the beginning oi
the program)
7: 00000000 1: 00000000 links the file Into the system)
8: 00000001 2: 00000001
9: 00000000 3: 00000000
10: 00000000 4: 00000000
11: 0000011A 5: 0000011A
12: 000003E9 6: 000003E9
13: 0000011A 7: 0OO0011A
14: 4E55FEA4 8: 4E55FEA4
15: 48E73F32 9: 48E73F32
As you can see from the hex dumps above, the files are
identical except that the first six longwords have been re
moved in the FFS. Also, the FFS begins with the data in the
first slot, while the old file system (OFS) begins in the sixth
slot. This means that each data sector can hold an extra 24
bytes of information under the FFS. When I compared the
storage on my two study disks, I found this:
DF2:
DF3:
879K
879K
1708
1648
50
110
97%
93%
0
0
Read/Write
Read/Write
OFS
FFS
Here you can see that the FFS saved me 4% of the floppy
disk storage space and left an additional 60 blocks free (this
is one advantage of using the FFS for floppies). The amount
of extra storage space will vary. If there are many small files
on the disk, the savings will be negligible, as each file has the
same overhead. If there are a few large files, however, the
extra storage space can be considerable.
Extra space is not the only advantage of the new filing sys
tem. When you load a file from the old file system, the system
puts it into a disk buffer, strips off the 24 bytes of nondata,
moves it into the user buffer, and then joins it to the remainder
of the file. Under the FFS, this process is skipped altogether,
and the data goes directly to the user buffer. Without that in
termediate step, the computer can call for several contiguous
blocks at a time, making an even larger savings in time.
There are some consequences, however, to using the Fast-
FileSystem. These are mostly in the area of file recovery. Un
der the old system, the 24 bytes in the first six slots contained
the position of this block in the file and the number of the
block containing the next chunk of data. That information is
helpful in rebuilding a ruined disk.
With the FFS, we are dependent upon the information con
tained elsewhere, although some of the information we need
is still present. Each sector on the drive has a sector label that
contains a sync mark to help the head position itself properly
for reading. It also contains data on the drive's format type,
the track and sector numbers, a checksum for the header and
the file block, and 16 bytes that are reserved for future use.
Continued on p. 47
The AW Tech journal 33
In Search of
The Perfect Joystick Routine
Looking for efficiency in all the "wrong" places.
By Rhett Anderson
ON THE AMIGA, there's usually a right way to program
(the Intuition, multitasking way) and a wrong way. When
programming to read a joystick, the right way consists of us
ing the Gameport device. For assembly-language game pro
grammers, however, the Gameport device is difficult to set
up and read and, worse yet, it is much too slow.
Even if you're sworn to uphold the purity of the ROM
Kernal Manual, it never hurts to know how the underlying
hardware works. For that reason, I'm going to show you how
to read a joystick the "wrong" way; that is, how to read the
hardware directly. Although my examples are written in as
sembly language, the techniques I use may give you ideas
for optimizing programs in your language of choice. As you
will see by the final result, the wrong way of doing things
can sometimes be right.
I'D RATHER SWITCH THAN SWITCH
Although the Amiga can use the proportional joysticks
common on such machines as the Apple II, Tandy Color
Computer, and PC compatibles, by far the most common
kind of Amiga joystick is the type that originated on the Atari
2600 VCS game system and was adopted by Commodore. It
offers four switches, each of which represents one of the car
dinal directions: up, down, left, and right.
Older systems, including the C-64, can read the joystick
simply by peeking bytes; each switch controls one of the bits.
On the Amiga, however, the joystick is surprisingly difficult
to decipher. The up and left switches control the two lowest
bits in a byte, while the down and right switches occupy the
two lowest bits in the neighboring byte. While you can read
the left and right switches directly (a 1 means the joystick is
pressed in that direction), reading the up and down positions
is more complicated. You must use exclusive or (EOR) on the
right and down bits to read the down direction, and on the
left and up bits to read the up direction. (It never fails to
amaze me what a hardware designer will do to save a few
logic gates!)
When I first attempted to write a joystick-reading routine,
I came up with Program 1 (see Listing.l in the accompanying
disk's Anderson directory). On entry, the routine assumes
that the port number is in register DO. Most Amiga users keep
a mouse plugged into port 0 and a joystick plugged into port
1 and will go to the trouble of plugging a joystick into port
0 only for a two-player game. For this reason, it is generally
safe to assume that a one-player game will use port 1 for the
joystick.
On exit, registers DO and Dl each hold a value of -1, 0,
or 1. DO is used for horizontal values and Dl for vertical val
ues. For instance, if the joystick is pressed down and to the
left, DO will be -1 and Dl will be 1.
CODE ON THE TABLE
If you value efficient, readable code, you will probably be
as disappointed with Listing.l as I was. The amount of
branching involved is little short of absurd. There's plenty of
room for improvement here (we could start by switching the
MOVE.W immediate instructions to MOVEQ, or move quick,
instructions), but a program like this needs far more than
tweaking.
Assembly-language code such as Listing.l begs for a
lookup table. To build a lookup table for this project, I used
the information received from the joystick as an index into
a data table. My first problem was in finding a way to group
the four important bits together. Here's what the data looked
like when I read a word (16-bit) value from hardware loca
tion $DFF00A (known as joyOporr) or $DFF00C (known as
joylport):
Value from SDFF0OA:
xxxxxxLUxxxxxxRD
(Note: Although the Amiga's hardware register base is
SDFF000, this value is not sacred. The proper way to get the
hardware base is by using the symbol -.custom, which is de
fined in the include file hardware/custom.i. As the include
file says, do this to get the base of custom registers: XREF _
custom. Directly accessing the hardware is not ideal, but
most programmers agree that Commodore will not change
the hardware base value—doing so would simply break too
many programs. While I generally recommend playing it
safe, for this example I'm throwing caution to the wind.)
Here, an x means that the bit has no relation to the joy
stick's position. Remember, up is really L EOR U, and down
is really R EOR D. If you wanted to, you could turn D and
U into the true down and left values with this section of code
(from Listing.l):
move.w $dffOOa,dO
move.w dO,d1
and.w #$202,d1
Isr.w#1,d1
eor.w d1,dO
and.w #S3O3,dO
In this example, I masked off the L and R bits, shifting them
to the right, and used exclusive or to join them with the D
and U bits. You do not really need to do this, however, as
you can take the exclusive or patterns into account in the
34 April/Ma}/ 1991
~
%
lookup table. You do need to group the four significant bits
together. After trying several options, I decided to rotate the
lower byte two bits to the right, which gave me:
xxxxxxLURDxxxxxx
That's perfect, except that we will want to shift this value
five places to the right so as to use it as an index into the
tables. (Normally, you would shift it six places to the right,
but here we need to look up the value of a table of words,
not a table of bytes.)
With a debugger running, 1 held the joystick handle in all
nine possible positions and watched the resulting values
stream into the Amiga:
DIRECTION
none
down
down,right
right
up
up.right
up.left
left
down, left
LURD
0000
0001
0010
0011
0100
0111
1000
1100
1101
DECIMAL
0
1
2
3
4
7
8
12
13
This allowed me to build one table for horizontal positions
and another for vertical positions. In the following tables, an
X indicates a "don't care" condition; that is, a value that can
not be obtained with a standard joystick (for example, press
ing the handle up, down, and right all at once).
Vertical dew 0, 1, 1, 0,-1, X, x,-1,-1, X, X, X, 0, 1, X, X
Horizontal dew 0, 0, 1, 1, 0, X, X, 1,-1, X, X, X,-1,-1, X, X
When using two lookup tables that include don't-care con
ditions, you can increase efficiency by embedding one table
within the other or by overlapping the two. In this case, we
can slide the horizontal table five words back into the vertical
table to save ten bytes. Also, we can ignore the last two words
of the horizontal table outright for a total savings of 14 bytes.
Here's the result:
Vertical dew 0, 1, 1, 0,-1, X, X,-1,-1, X, X
Horizontal dew 0, 0, 1, 1, 0, 0, 0, 1,-1, X, X, X,—1,-1
Admittedly, this change took a bit of lateral thinking. If you
are not convinced that this will work, just try it. Assume the
joystick is pushed down and to the left. As is shown in the
decimal-values table given us by the debugger, the index for
this joystick position is 13 (13 words from vertical is 1; 13
words from horizontal is — 1). You can verify this by checking
all the examples against the tables. In the final code, I re
placed the Xs with zeros.
A CLOSER LOOK
Let's look at the final code piece by piece:
move.l #$dff00a,a0
add.w dO,d0
move.w (a0,d0.w),d0
This section of code moves the hardware value of the joystick
into the DO register. If DO is 0, the value in $DFF00A (port 0)
is moved into DO. If DO is 1, the value in SDFFOOC (port 1) is
moved into DO.
Following the Amiga convention of treating registers DO,
Dl, A0, and Al as scratch registers is a wise practice. If you
use other registers in your routines, be sure to save them to
the stack at the beginning of the routine and restore them at
the end. Note that the last instruction above uses DO as both
an index and a destination. We will not need the port value
after this instruction, and there's no sense disturbing other
registers if you do not have to.
The following set of instructions merges the four direc
tional bits together in the form OOO0000OOOOLURD0:
ror.b #2,d0
Isr.w #5,dO
and.w #30,dO
The ROR instruction groups the bits, while LSR moves them
into reasonable numbers for an index, and the AND instruc
tion masks out any unwanted bits (the value 30 is 11110 in
binary). The possible results of this code are, in decimal: 0,2,
4, 6. . . .26, 28, 30. If you wanted to look up bytes instead of
words, you would use ROR.B #2,dO; LSR.W#6,dO; AND.W
#15,dO instead. (In fact, you can cut the table size down by
half by using bytes.) Then, before you return from the sub
routine, you could use EXT.W DO and EXT.W Dl to extend
the byte values to words. This, however, would be a trade of
speed for size.
For the final section of the routine, I present two alternate
sections of code:
lea Y,a0
move.w (aO,d0.w),d1
move.w 22(aO,d0.w),dO
rts
Y dew 0,1,1,0,-1,0,0,-1,-1,0,0
X dew 0,0,1,1,0,0,0,1,-1,0,0,0,-1,-1
Continued on p. 47
The AW Tech journal .35
An Amiga Basic
Graphical User InterfaceBring your interface into the modern age with gadgets and requesters.
A few subprograms are all you need.
By Bryan Catley
PRACTICALLY A "MUST have" for new programs, a
Graphical User Interface (GUI) is merely a full-screen, point-
and-click working environment. Text input, when necessary,
is provided via specially designed requesters. Unfortunately,
Amiga Basic provides no direct access to the operating sys
tem routines usually called to create a GUI.
Amiga Basic does directly support, however, many line
drawing and graphics functions, the mouse, and a method
of looking at each key press as it occurs. Why not use these
readily available facilities to simulate the built-in routines
that are so difficult to use from Amiga Basic? The basic idea
would be to create a number of subprograms, each of which
performs a predetermined task such as drawing a selection
of gadgets, checking which gadget was selected by the user,
accepting keyboard input from the user while providing full
editing facilities, providing a text input requester, and so on.
Yes, designing and setting up these subprograms requires
some effort, but once they are available you can simply
merge them into a program any time you need them, cutting
subsequent development times considerably. (To save you
even more time, I designed several for you already.)
To develop such subprograms, you need to store infor
mation about the (pseudo) gadgets, draw any specified range
of gadgets into the current window, check which of a spec
ified range of gadgets has been selected by the user and high
light that gadget, handle text input in a manner that gives
the user all the necessary editing facilities, and implement a
requester. You can find all of these capabilities via the readily
available and standard Amiga Basic facilities.
PROCESSING GADGETS
Because the embossed gadgets are currently in vogue,
we'll use this style in the example. The first thing we want
to be able to do is store information such as the gadget's lo
cation, size, colors, and text. It will appear in the main pro
gram as DATA statements, and the first subprogram will read
these and store the information in the appropriate of two
arrays—one for numeric information and one for text. (Note
that for the embossed style, you need three palettes, each
containing a light, medium, and dark shade of the same basic
color; this may mean you will need additional palettes
which, in turn, may require the use of a custom screen.) This
subprogram, called StoreGadgetlnfo, will be used once dur
ing program initialization.
Next we want to be able to draw any specified range of
these gadgets. This requires a subprogram that simply goes
into the arrays and draws gadgets based on the given range
and the contents of the arrays accessed. The main program
36 April/May 1991
uses this subprogram (DisplayGadgets) each time a new win
dow, which contains gadgets, is opened.
Finally, we need a subprogram that can check which of a
given range of gadgets has been selected. The selected
gadget should also be highlighted in some manner as long
as the user keeps the mouse button pressed. In our example,
we will change the embossed style to recessed for highlight
ing. This subprogram (CheckOnGadgets) will be used each
time the program waits for the user to select a gadget.
Now, let's look at an example of each subprogram in
depth. Check the Catley directory on the accompanying disk
for a listing of each.
GADGETS
StoreGadgetlnfo Of the three subprograms, this is by far
the most straightforward. It simply reads the DATA state
ments defining the gadgets and stores the information in the
appropriate arrays. The listing (GadgetSubs) shows the nec
essary format for the DATA statements. One point worthy of
note is that the names of the gadget arrays are set up as
shared variables. This means that once defined, the same
names must be used at all times. (If you wish, you could use
multiple arrays and pass the array names to each of the sub
programs as additional parameters).
DisplayGadgets This subprogram simply draws all the
gadgets within the range specified as input parameters. Note
that DisplayGadgets uses the operating system routines
Move& and Text& to position and display the text within the
gadgets, letting you place the gadgets at any pixel location
within the window. It also requires the use of graphics.library
in the form of a graphics.bmap file in your libs: directory. If
you are careful to always position the gadgets at multiples
of eight, you may use the standard Amiga Basic LOCATE and
PRINT commands, instead.
As coded, the gadgets should be no more than eight pixels
high because of the method used to position text within the
gadget. If you wish to use larger gadgets, you will need to
modify the text positioning code.
The x,y + 6 in the positioning code sets the drawing point
for the text string's baseline (assuming an eight-point font).
If you use alternate fonts, you must modify the height of the
gadgets and adjust the y + 6 for the new font's baseline. This
may require additional parameters or shared variables.
CheckOnGadgets The most complicated of the three
subprograms, CheckOnGadgets takes the mouse coordi
nates and compares them to the stored gadgets within the
range specified. If found, the gadget is highlighted and the
selected parameter is set to the relative number of the gadget
^
~
selected within the range specified. For example, if the range
specified is 20 to 25 and the user chooses the 22nd gadget,
the subprogram sets the selected parameter to 3. The high
lighting remains until the user releases the mouse button.
Note that there are three shared variables which play no di
rect role in the function of this subprogram. They are present
for the potential use of the caller and other subprograms. For
example, if a gadget is set up as a slider gadget (such as Pref
erence's color gadgets), then not only do you need to know
that the gadget was selected, but also where in the gadget
the mouse pointer was clicked; MouseX% and MouseY%
make this information available. The MousePress variable is
used by the Userlnput subprogram, which we'll discuss later.
To see these subprograms in action, copy the Gadget-
Demol program and GadgetSubs to your Amiga Basic disk,
run AmigaBasic, load GadgetDemol, and then merge
GadgetSubs. Now, run the resultant program.
TEXT INPUT
No matter how complete a GUI is, at some point the user
will be required to enter some sort of specific textual infor
mation, such as a filename. When you look at the methods
provided by Amiga Basic, however, you find not many are
appropriate to a GUI. What we really want is a facility that
provides, at a minimum, the capability to move a cursor back
and forth without impacting the current text string, to back
space over characters (deleting them as it goes), to delete the
character under the cursor, and to insert new characters at
the current cursor position. Now, Amiga Basic does provide
an INKEY$ function that allows access to each key press. If
we know where we are in the current window, we can com
bine INKEY$ with a cursor that is nothing more than an 8 x 8
area which is placed in position, and subsequently erased
(moved), with the PUT (XOR option) command.
Take a look at the subprogram named Userlnput as an ex
ample. It also allows the user to erase the entire text string
and start anew just by pressing the ESC key.
Userlnput The necessary parameters are described in
the listing. The major thing to note is that, like the gadget
subprograms, Userlnput uses the Move& and Text& oper
ating system routines to position and display the text. Other
than that, the subprogram simply waits for a key press (or
an indication that a gadget has been selected), checks which
key it is, and acts accordingly. If a gadget was selected,
Userlnput does nothing further and returns to the caller so
the gadget selection may be processed. This is the purpose
of the MousePress variable. For a demonstration of how this
subprogram works, load TextDemol, then merge Userlnput-
GadgetOemol creates the gadgets and monitors mouse action.
RequesterDemd combines button gadgets and an editable text gadget
Sub, and run the resultant program.
PROGRAM REQUESTERS
Requesters are essentially a combination of prompts, (op
tional) text input, and gadgets all contained in a small
window that opens when the user selects an option that war
rants the use of a requester. Once again, the Move& and
Text& routines display the prompts.
The major complication is the fact that the text input and
the gadget checking routines must have some means of com
munication. For example, what if the user enters some input
but clicks a gadget before pressing the return key; or what if
the user presses the return key but then decides the string
just entered requires modification? A requester must provide
for all these eventualities. On the accompanying disk, you
will find a set of two subprograms (RequestData and YesNo)
stored collectively under the name Requesters.
RequestData asks the user for input and provides Ok
and Cancel gadgets; the required input parameters are de
fined within the listing. The most important facts to note are
that the colors used, the positioning of the window, and the
maximum size of the text string to be entered or edited are
somewhat arbitrary. Feel free to modify these values to suit
your own preferences or those of your main program. Note
that any modifications will probably require changes to the
shared variables and possibly the DATA statement that de
fines the text input area. The positioning of the Ok and Can
cel gadgets may also require adjustment.
YesNo This requester simply waits for the user to select
a Yes or No gadget based on given prompts. Once again, the
positioning and colors used are somewhat arbitrary and may
Continued on p. 39
The AW Tech journal 37
The Amiga Zen TimerSpeed up your assembly code with the help
of this software stopwatch.
By Dan Babcock
WHEN WRITING TIGHT code on a tight schedule, you
cannot afford to guess at optimizing it, merely juggling in
structions based on intuition. Profilers are great for identi
fying the hot spots that consume the bulk of execution time,
but they offer no help in fine-tuning these performance-crit
ical chunks. You could consult the official instruction timings
in Motorola's MC68000 manual, but the workings of a CPU
are simply too complicated to be explained by a few rules or
a table of numbers. True execution speed depends on the
order and sequence of instructions, the state of the prefetch
queue, DMA contention, and other factors. For the best re
sults, you need to take real-world measurements.
VIDEO TIME
Programming one of the CIA timers is a solution, but an
inaccurate one. These timers yield a resolution, roughly
speaking, of ten MC68000 cycles. For superior results, use the
Amiga's built-in video beam counter. This counter has a res
olution of one color clock, which equals 279.3651148 nano
seconds, assuming your system has an NTSC-type oscillator
(28.63636 MHz). Stated another way, it sounds even better:
One color clock equals two MC68000 clocks. Because all
MC68000 instructions take an even number of clock cycles to
complete, the beam counter provides a perfect timer. This
counter is very useful for measuring the speed of a blitter
operation, as well.
Don't worry, the horizontal blanking period does not in
troduce a discontinuity in the beam counter. The beam
counter increments in a uniform manner for an entire display
frame. I have, however, observed quirky behavior at the end
of a frame. To avoid this problem, start timing at the second
scan line of a display frame.
Building a timer program around this counter is relatively
simple. Find the x,y coordinates of the video beam by taking
two samples of the beam counter, one just before the test
code and one after. After the test, compute and display the
elapsed time using the stored beam counter samples. This is
easy to do, when you know that in NTSC mode one scan line
equals 227.5 color clocks (in PAL, one scan line equals 227
color clocks). Multiply each y by 227.5 (227) then add the ap
propriate x to determine the number of color clocks. Finally,
you subtract the overhead of the timer to yield the final re
sult. (Take a look at zen.i in the Babcock directory on the
accompanying disk for a complete listing.)
Using the timer to time itself seems paradoxical, yet that is
exactly what you do. The idea is as follows: Start and stop
the timer with no intervening code. If the code to begin and
end a timing session introduced no overhead, the result
38 April/May 1991
should be zero. It is not zero, of course, but is exactly equal
to the overhead of the timer.
BEAT THE CLOCK
When using the Zen Timer you need to keep a few restric
tions in mind. The macros ZTimerOn and ZTimerOff start
and stop the timing, respectively. Using this technique alone,
you cannot time a code sequence longer than about 20 mil
liseconds (the PAL display period). If the maximum time is
exceeded, the program prints an error message. Secondly,
because the ZTimerOn turns off all interrupts for accuracy,
your code cannot depend on interrupts, and almost all op
erating system calls are off-limits. The whole purpose of the
Zen Timer is to measure the performance of relatively short
code sequences, so this should not present a problem.
To view the results, perform a JSR or BSR to ZTimerReport.
ZTimerReport computes the time spent in the code sequence
between ZTimerOn and ZTimerOff, subtracts the timer over
head, and prints the results, in color clocks, to the so-called
"standard output," normally the CLI. You need not call
ZTimerReport immediately after performing a ZTimerOff.
You are encouraged to modify this routine to suit your needs
and preferences.
Consider the example:
;An example use of the Zen Timer
^Assemble with Macro68
exeobj
objfilo 'testzen'
Include 'zen.i'
ZTimerOn
;Your code goes here.
nop
ZTimerOff
bsr ZTimerReport
moveq #O,dO
rts
end
When you assemble and run this example, it prints to the
CLI:
2 color clocks.
This tells you the system took four MC68000 cycles to execute
the NOP instruction, exactly as expected.
As I said before, the Zen Timer is capable of timing small
code sequences, even only one instruction. There is one
catch, however: The execution speed of the first instruction
is dependent to a certain extent on the state of the prefetch
The Amiga Zen Timer
~
^>
queue. As a result, some caution is required.
Now, try adding NOP instructions to the example code. Each
NOP should add exactly two color clocks to the execution time,
assuming that code is run in zero-wait-state fast memory. In
chip memory, the timings will vary slightly with each execution.
For accuracy, you should always run a timing test several times
and then calculate the average execution time.
Let's turn to a more interesting example. Suppose your
code accesses the CIAs (or another chip that is accessed in a
similar way). We know that the CIAs are accessed on ten-
cycle boundaries. How should you arrange the code to min
imize the synchronization delays? Ask the Zen Timer. When
you run the code below, you will discover that the system
executes it in between 26 and 30 color clocks.
;CIA access example
exeobj
objfile 'testzen.cla'
Include 'zen.l'
ZTlmerOn
move.b (SbfeOCM).dO
move.b (SbfeOO1),d1
ZTimerOff
bsr ZtimerReport
moveq -'/O.dO
rts
end
Now try:
;CIA access example 2
exeobj
objflle !estzen.cia2
Include 'zen.i'
ZTlmerOn
move.b (SbleOO1),d0
nop
nap
move.b (SbfeOO1),dl
ZTimerOtf
bsr ZTimerReport
moveq #0,d0
rts
end
This routine adds two time-wasting NOP instructions.
Surprisingly, the timing results are exactly the same as for
the previous example! Add one more NOP instruction, how
ever, and you add a full ten MC68000 cycles to the execution
time. Upon discovering this in a real program, you should
try to fill the eight cycle void with a useful instruction, such
as an address calculation (adda.l d2,al) that the routine may
need later.
As you can see, the Zen Timer lets you stop guessing and
start timing! Use it on your own "efficient" routines; you may
be surprised by the results. ■
Dan Babcock is an electrical engineering major at Pennsylvania
State University and an avid assembly programmer. Write to him
c/o The AmigaWorld Tech Journal, 80 Elm St., Peterborough,
NH 03458.
Graphical User Interface
From p. 37
be modified. Any modifications may require changes similar
to those described for RequestData above.
For a demonstration, load RequesterDemol, then merge
GadgetSubs, UserlnputSub, and RequesterSubs, respec
tively, from the accompanying disk and run the resultant
program. Note that a mouse interrupt routine is used in this
demonstration, which is of particular importance should
your program also include custom menus, (simply add a
menu interrupt routine, along with the one for the mouse,
to give you complete control over everything the user may
desire). You may also want to add an additional shared vari
able to the Userlnput subprogram to detect a menu selection
when it is made. A better approach is to temporarily turn off
the menu interrupt when a requester is invoked.
These six subprograms provide the basis for a simulated
Graphical User Interface and may be used in virtually any
Amiga Basic program, if you bear two things in mind. First,
consider your own expansions to the capabilities described
here. For example, modify Userlnput to position the cursor
directly over the character selected rather than always high
lighting the first character. Second, if you use these subpro
grams with large programs that are not compiled, there will
be noticeable delays the first time the various subprograms
are used. Unfortunately, you cannot change this, it is just
Amiga Basic rearranging memory for its own purposes. ■
Bryan Catley has been writing and programming for Amiga pub
lications for many years. Write to him c/o The AmigaWorld Tech
Journal, SO Elm St., Peterborough, NH 03458.
A'MA-S■THE ADVANCED MIDI AMIGA SAMPLER
This stylish hardware unit provides your Amiga with full B-bil siereo
digitizing capabilities p|ug a lull implementation midi interface - all in the
Game unit! The beautiful graphics/mouse software interface has dual
real-time oscilloscopes and complete sound F/X manipulation tools
including reverb and echo. The midi-support is provided in landam with
the digitizing software.
This is lhe software featured in the Paula Abdul video. "Cold-Hearted
Snake* Check it oui!
3201 Drummond Plaza
Newark, DE 19711
(302) 454-7946
The AW Tech journal 39
Reviews
From p. 22
gram. I was assured a supplementary
Algebra package, not available at the
time of this review, will construct such
a loadable file.
REWRITTEN RULEBOOK
The documentation and examples pro
vided on the Algebra disk break many
of Commodore's style rules. Peeking
and poking memory locations, other
than address 4, is taboo by Commo
dore standards. Yet, Algebra happily
suggests diving into hardware regis
ters directly or passing values to and
from subroutines by poking them into
fixed locations. You can do all this, of
course. It's your machine and you
won't go up in flames the instant you
break a rule. Normally, however, you
should treat your multitasking Amiga
with courtesy to avoid stepping on an
other task or building incompatibilities
that will obstruct future system expan
sion. I do worry that beginners will
start with these techniques before they
understand the dangers. I wish the
documentation and the examples were
more conservative.
For me, Algebra is not a viable choice
with so many first-class assemblers
available. Its syntax is highly individ
ual—too much so if you want to under
stand assembly language listings in
books or magazines. If you can't grasp
the standard method, however, Algebra
will produce workable code and may be
the starting point you need.
Macro68
The Puzzle Factory
PO Box 986
Veneta, OR 97487
503/935-3709
$150
One megabyte required.
Algebra
Aelen Corp.
529 W 42th St.
New York, NY 10036
$89.95
No special requirements.
The QPMA BASIC
Programmer's Toolkit
In search of a better PSET.
By Robert D'Asto
SQUEEZING GREATER performance
from Amiga Basic graphics is a subject
near to the hearts of many program
mers. The language is easy and fun to
use, but, unaided by lower level tech
niques or LIBRARY calls, it merely taps
the throttle of the mighty graphics en
gine that lies below. With the Amiga's
available palette of 4096 colors, BASIC
provides direct support for no more
than 32 at a time. This graphics per
formance gap creates a void for clever
programmers to fill with tricks,
tweaks, PEEKS, and POKES, as well as
a variety of para-BASIC extenders, ex
panders, and supersets.
One recent solution is The QPMA
BASIC Programmer's Toolkit from
High Byte Software. Their claim, "al
lows Amiga Basic and AC/BASIC pro
grammers to easily produce graphics
in the new QPMA graphics mode,
which features 320x200 resolution
with 136 simultaneous colors from a
total palette of 8.39 million colors [and]
requires no special hardware," caught
my immediate attention. Promising
"color flexibility comparable to HAM
Mode with none of HAM's problems"
and "no complex screen slicing tech
niques," it fired my curiosity. All those
features for only about $30? This I had
to see.
The QPMA package consists of a
single, nonbootable disk without copy
protection that contains the Toolkit,
two Read.Me files of documentation,
and several Amiga Basic and AC/
BASIC examples of QPMA program
ming. The toolkit itself is an Amiga Ba
sic source code "shell" into which you
insert your own code. This shell holds
the definitions of 17 Amiga Basic sub
programs that provide the aforemen
tioned graphics mode.
WHAT'S NEW?
The term QPMA, the documentation
instructs, stands for "Quad-Pixel Ma
trix Array. . .and can be best described
as a virtual graphics mode." The text
goes on to explain how QPMA works.
The author of this program discovered
that placing two different-colored pix
els next to each other on the screen
produces the optical illusion that a
third color, which is a combination of
the two, is being displayed—sounds
an awful lot like dithering to me. The
documentation does later identify this
technique as dithering and states, "Up
until now. . .[dithering] has been hard
to program, and. . .there was no
standard all-dithering graphics mode
like QPMA. Dithering, for the most
part, was practical only for digiti2ers.
Until now." Really? I could have
sworn I'd seen practical dithering in
various graphics utilities from com
mercial paint programs to PD icon edi
tors, and programming it in BASIC
always seemed a snap via the PAT
TERN and COLOR statements. But
never mind that.
The text continues to explain that
the QPMA system renders geometric
shapes in four-pixel blocks on a hi-res
interlaced screen. Each block contains
two pixels of one color and two of an
other, in checkerboard fashion. This
hi-res pixel block has an appearance
similar to a single pixel on a lo-res
screen, drawn in the color resulting
from the combination of the two that
make up the hi-res block. Because it
uses a screen with a depth of four bit-
planes, capable of producing 16 differ
ent colors, a total of 136 apparent
colors are available when all possible
pairs of the basic colors are dithered.
In short, the QPMA system is dither
ing two colors at a time on a 640 x 400
screen in a manner that simulates the
appearance of a 320 x 200 display, ex
cept that the programmer must now
contend with the problems of flicker
and the tiny text inherent in interlaced
screens.
Where, then, is the promised new
graphics mode, comparable to HAM,
but with none of its problems? Read
ing through the documentation sev
eral times and studying the QPMA
subprograms, which contain only
standard Amiga Basic commands, I
came to the conclusion that drawing
graphics with QPMA is simply dither
ing on an interlaced screen and noth
ing more.
Dithering has been with us longer
than the Amiga. Calling this a new
graphics mode or even a virtual
graphics mode and stating that it of
fers color flexibility comparable to
HAM is simply misleading. I concede
that dithering could be referred to as a
graphics mode, but it is not new, and
the simultaneous display of 136 appar
ent colors is in no way comparable to
HAM's 4096 true colors. As for the to
tal palette of 8.39 million colors, the
docs explain that this is the number of
possible two-color, dithered combina
tions of the Amiga's 4096 actual colors.
Sorry, it doesn't work that way. A pal-
40 April/May 1991
Reviews
ette is the total number of true colors
^—-- available, not apparent colors.
To write a QPMA program, you load
the Toolkit into the Amiga Basic editor
and type the source code into the
space provided near the top of the file.
You begin by setting up a 640x400
screen with the normal SCREEN state
ment and then drawing graphic ob
jects by calling the various
subprograms provided at the bottom
of the file. The QPMA subprograms
act as replacements for the Amiga Ba
sic keywords MOUSE, PSET, POINT,
LINE, CIRCLE, GET, and PUT. In addi
tion, QPMASETBLOCK sets the de
sired dithering colors and the size of
the basic "building block" of pixels
used to render graphics. One remain
ing subprogram is used to determine
the required size of a graphics array
used for GET and PUT operations.
The routines do produce 136 appar
ent, dithered colors and are easy to
use. Because no subroutines replace
such keywords as PAINT and AREA,
however, the graphics rendered with
QPMA are limited to dots, lines, rec
tangles, boxes, and unfilled circles, as
far as I can tell. You could use normal
Amiga Basic keywords in addition to
the QPMA subs, but, as the documen
tation states, their output looks odd
when rendered next to the QPMA-
dithered objects.
PUT ON A HAPPY FACE
I followed the instructions and wrote a
program to render a single QPMA cir
cle with a 50-pixel radius in the center
of the screen. I first set the dithering
colors with the QPMASETBLOCK rou
tine and used the sub, QPMACIRCLE,
to draw it. I then added code to calcu
late the elapsed time required to draw
the circle. Finally, I signaled the inter
preter to run my program, sat back,
and watched the Quad-Pixel Matrix
Arrays at work. After 44 seconds my
circle was complete, smartly dithered
in the two colors I had specified. I ran
it again to be sure. Yes, it took 44 sec
onds to draw one, medium-sized,
QPMA circle. Concerned with the ren
dering time required to draw a more
complex design such as a happy face, I
timed the rendering of a single hori-
-—v zontal line running the width of the
screen: 15 seconds. At 44 seconds for a
circle and 15 for a line, that's almost a
minute without the eyes! I'm afraid I
~
never determined a final result for the
happy-face benchmark, as I knew it
would take longer than I was willing
to wait.
The documentation file highly rec
ommends compiling QPMA programs
with Absoft's AC/BASIC compiler to
speed up execution times. This
method is about three times faster
than the interpreter, but is still not fast
enough to make real-time graphics
rendering with QPMA practical. One
of the examples provided on the
QPMA disk is an AC/BASIC-compiled
demo that displays a number of verti
cal bars that rapidly change color,
showing off the 136 apparent hues
available with dithering on a four-bit-
plane screen. Drawing the bars takes a
while, but, once rendered, they flash
through their color cycles in admirable
style. The trouble is the colors are
changed via BASIC'S PALETTE state
ment, not with any of the QPMA rou
tines. The execution times for drawing
graphic objects in all the examples
were comparable to my own QPMA
programming efforts.
QPMA is an interesting example of
how simple, dithered graphics work.
Other than that, I cannot think of a
practical use for it. It may well have
value to BASIC tinkerers, but touting it
as providing programmers with a new
graphics mode having expanded color
capability comparable to HAM is just
not an accurate representation.
The QPMA BASIC
Programmer's Toolkit
High Byte Softzuare
91 Hillside St.
Wilkes-Barre, PA 18702
$29.95 (plus $2.00 S&H)
No special requirements.
FlexeLint 4.0
Sucks up errors like
a vacuum.
By David T. McClellan
THE FIRST C compilers merely turned
C into object code. They did not diag
nose problems, which made finding
code errors difficult. The situation
worsened when C compilers began
running on more than one machine
and portability bugs cropped up faster
than fungus in a refrigerator. So Ker-
nighan and his team invented lint, a
program that picks out problem bits of
fluff from a C program, such as func
tion argument type conflicts, uninitial
ized variables, size conflicts in
assigning pointers to ints, and using
different data types for the same argu
ments to a function. Lint helped turn
up many obscure bugs and also pre
tested code for portability.
FUZZ BUSTER
Gimpel Software's lastest Amiga ver
sion of lint, FlexeLint 4.0, offers much
more extensive C-fluff finding and
highly configurable error-reporting. It
runs fine on Lattice C and Manx Aztec
C programs, and can find subtle bugs
you introduced into code without no
ticing, especially the kind that don't
show up under normal tests. Asa cross-
development plus, FlexeLint, using a
large number of configurable code-
checking options, can be made to exam
ine C code as Microsoft C and PC or
Unix lint does. If you carefully separate
files with Amiga-specific parts from the
portable parts, this option is a great help
in catching porting problems early.
Take a look at the following badly
formed C program to get a feel for a few
of the things FlexeLint can find.
-'■include <stdio.h>
''include <math.h>
Adeline XINC 1
■■-'define DEBUGGING 1
"ifdef DEBUGGING
#define debmsg(x) printf("Debug msg:
%s\n",x);
//endif DEBUGGING
main (argc, argv)
Int argc;
char *"argv;
{
double dd, xx;
Int II;FILE "out;
if (Kout^fopenfourNle'VV)))
exit(1);
if {argc > 1)
dd = 25.0;
ii = sqrt(dd);
if (H ! ■ 5)
debmsg("Bad sqrt!" ;else
fprlnrf(out,"SQRT of %d is %d\n-\dd,ii);
lclose(out);
}
Now, here is FlexeLint's report on
the above mess:
#endif DEBUGGING
exi.e 9 Warning 544: endif or else not fol
lowed by EOL
if (!{out = fopen("outflle","w")}) »•
The AW Tech Journal 41
Reviews
exi.c 19 Into 720: Boolean test oJ assign
ment
extt(1);ex1.c 20 Info 718: exit undeclared,
assumed to return int
exi.c 20 Into 746: call to exft not made in
the presence of a prototype
ll = sqrt(dd);
exi.c 23 Warning 524: Loss of precision (as
signment) (double to Int)
prlntf("SQRT of %d Is %d\rf,dd,ii);
exi.c 27 Warning 559: Size of argument no.
2 Inconsistent with format
}
exi.c 30 Warning 533: Return mode of main
inconsistent with line 11
exi.c 30 Warning 529: xx (line 15) not refer
enced
exi.c 30 Into 715: argv (line 13) not refer
enced
— Wrap-up for Module: exi.c
Info 750: local macro XINC (line 4, file exi.c)
not referenced
— Global Wrap-up
Warning 526: exit (line 20, file exi.c) not de
fined
Warning 628: no argument Information pro
vided for function exit (line 20, file exi.c)
As you can see, FlexeLint caught a
number of subtle and not-so-subtle
glitches. Some compilers don't allow
anything after "#endif" (or#else for
that matter). While the"., .if (!(out =
fopen( ..." is legal here, it could
have been a mistyped version of
"... if (!(out = = fopen(..." , which
would be a mistaken assignment.
FlexeLint goes on to catch several
more errors, including use of exit( )
without a prototype, a double {long
real) being chopped down to an int
(losing precision, possibly fatally), and
a double being passed to a printf %d
format. At the end it told me that I de
fined but never used "argv", "xx" and
^define symbol "XINC"; "xx" and
"XINC" are thus unnecessary (or
placeholders for later). Most of these
the Lattice and Manx compilers would
not see, and would show up only
when you tested the code.
"CORRECT" ERRORS
If you anticipate seeing certain errors
often, because of your coding style or
the fact that parts of your code are
young, you can direct FlexeLint to ig
nore them. For example, placing the
command -e529 on the lint command
line tells FlexeLint not to report error
529 (unused variable) for any file it
processes. Alternatively, you could tell
it to ignore that error (or any other)
for a specific file or symbol, as in:
-efile(529,fred.c) (don't report It tor file
fred.c)
- esym(529,xx,yy,zzzzz) (ignore tor variables
xx, yy, and zzzzz)
Because FlexeLint can process many
files, in sequence, on its command line,
you could also turn off an error before
one set of files, then turn it back on for
another, as in:
lint -e529 fred.c barney.c wilma.c + e529
betty.c bambam.c
FlexeLint will ignore classes of mes
sages as well as individual ones. For
example, — eau tells FlexeLint to ig
nore cases in which a function expects
an unsigned number and you pass it a
signed one.
When you wish to ignore certain in
dividual errors or classes of reports
every time you run FlexeLint, you can
create a directive file with a text editor.
Directive files contain — e<number>
and other commands on separate lines
and have names ending with .Int. To
use such a file, type its name on the
FlexeLint command line before the C
files it affects, as in:
lint Mylgnores tred barney wllma
To save you even more typing,
FlexeLint tries appending first .Int and
then .c to filenames that don't have ex
tensions. The program would read the
names in the above command line,
therefore, as Mylngores.lnt, fred.c, bar
ney.c, and wilma.c, respectively.
Directive files are also useful for ex
plaining compiler eccentricities to
FlexeLint. To begin a port to Microsoft
MS-DOS C, you would create a mi-
cro.lnt file describing handling of near
and far pointers and so on, and then
use FlexeLint to check your code.
EXCLUDING INCLUDES
Unused defines and variables appear
all the time in include files, because
programs typically use only a subset of
an include's contents. This would
cause a lot of 529 and 750 errors,
among others, if FlexeLint did not
treat include files specially. When you
enclose a filename in angle brackets
(<>), FlexeLint considers the file to be
a "library" file and, unless told other
wise, ignores symbols that are defined
but not used. FlexeLint provides direc
tives for you to specify in great detail
which files or directories of files
should be treated this way, but the de
fault case works fairly well. It searches
for include files in the directory speci
fied by the — i directive just as Lattice
and Manx do. It will properly process
not only <stdio.h> and similar "stand
ard" include files, but also such
Amiga-specific ones as <intuition/intu-
irion.h>.
This brings me to FlexeLint's minor
problem. Lattice users, such as myself,
keep the include files in compressed
form, to speed their processing by the
compiler. FlexeLint cannot yet handle
these compressed files (Gimpel's
phrasing, so maybe in the future it
will). So you must keep your Compiler.
Headers floppy handy and pop it in
when you use FlexeLint. Also, Ftexe-
Lint will use the Manx-style environ
ment variable INCLUDE (set with
Manx's set command) to find include
files, but not the INCLUDE: device set
by the ASSIGN command for Lattice to
use. You can work around this, how
ever, with a sequence such as:
ASSIGN IN: Lattice :Compller_Headers
lint -UN: ...
or by putting the — i directive in a .Int
file. The string following — i, by the
way, is concatenated directly to in
clude file names, to avoid operating
system-specific filename constraints.
Put slashes at the end of your include
directory names if you specify them
on the command line.
CORRECTING THE TEACHER
I ran FlexeLint over a few of the pro
grams I wrote for tutorial articles. I
wish I'd had FlexeLint to use earlier; it
turned up a few things in those pro
grams that should not have seen print.
If you work on large amounts of C
code, particularly for projects you
hope to port to other platforms,
FlexeLint 4.0 is a must. ■
FlexeLint 4.0
Gimpel Software
3207 Hogarth Lane
Collegeville, PA 19426
215/584-4261
S98
No special requirements.
42 April/'May 1991
-— Do-lt-Yourself
Software MarketingStaking your claim as a software entrepreneur requires more than
a good concept and a fast-running program.
By John Foust, with Harriet Maybeck Tolly
WHETHER YOUR DREAM is to found the next Microsoft
or just to turn a tidy profit on your after-hours programming
projects, you face the same obstacles. In retrospect coding
your application or game may seem easy compared to han
dling the marketing, packaging, advertising, and distribu
tion. To map out the real costs and concerns of the software
business, let's start a one-product company called Little Ga
rage Software. To make it easy, we'll assume that you've al
ready written and thoroughly beta-tested the program.
The first thing you have to decide is how many copies you
think you can sell, so you know how many to make. Consider
the limiting factors: If your product does not compare fa
vorably with similar products in price and performance, sales
will suffer. If it's a programmer's tool, or appeals only to CL1
users, then the market is much smaller, but the program may
sell at a steady rate for a long time. If it's a game, sales will
be brisk for a few weeks, and then drop off to nothing.
Brashly assuming your product is positioned correctly and
fills a market need, let's look at typical sales figures for Amiga
products. The total number of Amigas sold puts a cap on our
estimate. While Commodore proudly states that a million
Amigas have been sold worldwide, that is over a five-year
period and split among the different models. Commodore
made approximately 150,000 Amiga 1000s. How many of the
million are A500s, and how many are A2000s?
Estimating that only about 30 percent of the Amigas were
sold in the United States. The best you can hope for is 300,000
sales, unless you also market your product in Europe and
Canada. If the product needs a lot of memory, a hard disk,
or a specific version of the operating system, the market
shrinks again. As a comparison, early sales penetration of
Electronic Arts' wildly successful DeluxePaint was once es
timated at 30 percent of all Amiga owners, but a very popular
Amiga product usually sells only about 10,000 copies in a
year. A moderately popular product sells 3000 to 7000 copies.
For a conservative estimate, plan to move 2000 copies.
GOING IN THE HOLE: PRODUCTION COSTS
The second most important part of the program package
is the manual. Hiring a professional writer to create a small,
30-page manual costs around S1000, so save money and write
it yourself. You can design and print a bare-bones manual on
a letter-quality printer with a simple word processor, but
desktop-publishing software and a laser printer bring better
results—at a greater cost, of course. Let's assume you're lucky
enough to have access to the best printer and software.
Your printer is fine for one copy, but what about the other
1999? Offset printing runs at about three cents a page in vol
ume. Let's say the manual is 30 pages long, and each page is
half the size of a regular sheet of paper. Printing a half page
on both sides costs the same as printing a full page on one
side, so duplication for the manual comes to about one dollar
apiece, plus 15 cents for a printed cardboard cover and two
staples in the binding.
For packaging, simple one-color cardboard sleeves cost
about 30 cents each. As long as you have the desktop-pub
lishing software, you can design and print these yourself, as
well. If you have your heart set on 4-color boxes, be prepared
to shell out SI.75 apiece for preparation and printing.
With two drives and a copy program, 2000 disks will take
quite a while to duplicate, and then each one must be labeled.
Custom-printed labels cost about 15 cents each. Disk-dupli
cation services charge about 25 to 50 cents a disk for copying
and labeling. Hire the service.
To shrink-wrap the packages with the manuals and disks
inside, an outside company charges close to 25 cents a pack
age (S500 for 2000). If you do it yourself, shrink-wrap ma
chines cost S300 or so, plus plastic. At a rate of one minute
per package, you will finish in a minimum of 33 hours.
Adding 50 cents for such incidentals as printing a warranty
card and driving around town on errands, the cost for parts
comes to S3.05 per package. For 2000 copies, then, you need
at least $6100 to start Little Garage Software, and you will not
recoup that for at least several months.
A good rule of thumb is that the retail price should be four
to five times the production costs. With a raw-parts cost of
$3.05, the price would then be $12.20 to $15.25. You haven't
paid yourself yet, however, or amortized fixed costs over the
product's lifetime. For the sake of argument, let's set the pro
gram's retail price at $49.95. Now you need to find people
who will pay that.
THE BIG SPLASH: MARKETING
Advertising is a must, but it's not cheap. The most inex
pensive national Amiga magazines charge approximately
$1500 for a full-page black-and-white ad and S600 for a
quarter-page ad. The circulation leader charges about $1500
for a quarter-page ad, a higher rate because it reaches more
people. Color ads are roughly S6500 a pop, plus another $500
for color separations. Before publication, someone must
write the ad, compose it, and supply camera-ready art to the
magazine. For color, hire a professional. You could make a
small, black-and-white ad yourself, but small ads cannot
carry much information and do not have the eye-catching
appeal of full-page color.
Afraid you can't afford to advertise? Editorial coverage in i
The AW Tech journal 43
Marketing
magazines puts your product's name before the public, too.
To get the program in front of the editors, you must write
and print a press release to announce the product, and then
mail at least 100 copies. You should also send out a dozen or
so review copies, but this gambit can backfire. A good review
will enhance sales, but a bad review could permanently dam
age them. In either case, you won't see the review until two
to six months after the magazine receives the product.
Trade shows are a more immediate—but expensive—way
to alert the public. If you have a superior product, you might
get a small space in Commodore's booth at a show such as
COMDEX. The chances are, however, that space is limited
and your product isn't flashy enough. A booth at a recent
AmiEXPO {now called AmigaWorld Expo) cost S1600, plus
S300 for renting furniture, carpeting, and electricity. You'd
need to compose and print flyers and press releases, box up
Amigas and monitors, make decorations and signs for the
booth, and ship it all to the show. Once the equipment is
there, the labor union charges to move it to your booth. Now
add the cost of airline rickets, downtown hotel bills and taxi
service, and you could easily sink $4000 into the event. If
you're lucky, sales at the show will recoup these costs.
Imagine all the other costs of doing business: a separate
phone line for arranging production, distribution, and press
coverage (not to mention technical support), a database for
invoicing distributors, dealers, and direct-mail sales; an an
swering machine, office supplies, postal scales, postage me
ters, letterhead, business cards, Federal Express and UPS
accounts. Where will you put all this stuff? Business supply
stores sell mailing envelopes and such in lots of 1000, not 50;
you'll need a chunk of cash up front and lots of storage space.
Don't forget government paperwork, either. You need a
local business permit, a state sales tax number, a federal tax
ID number, and local sales tax permits for every trade show
where you sell the product. The frequency of filing sales-tax
returns depends upon the volume of sales in a particular
state. With all this money and paper flowing around, you
should hire an accountant and lawyer. Open a separate
checking account, as well, to make sorting out the business
taxes easier.
To pay yourself, you must file quarterly Social-Security
and income-tax reports. To minimize liability, it would be bet
ter to opt for incorporation, as opposed to sole proprietor
ship. Incorporating, however, increases the cost of filing
taxes, and the cheapest possible incorporation still runs to
several hundred dollars. For further protection, you should
trademark your program's name and search for conflicts
with other product names, at a tune of several hundred dol
lars per name.
RING IT UP: SALES
You will take in the most money (almost S40) on a direct
sale to a customer, but few people buy straight from the man
ufacturer. That S40 is not pure profit, either. For each direct
sale, you need to make invoices and keep records, plus pack
and ship it. This time and effort mounts up quickly, especially
when you add the direct-sales payment hassles. What if a
check bounces? How do you collect it? Do you delay ship
ment until the check clears? Should you mail C.O.D? Getting
credit card privileges from a bank is very difficult. In many
states, you cannot legally accept credit card orders unless you
are a corporation with a customer store front.
Selling through a distributor is more common and advan
tageous. One shipment to a distributor replaces dozens of
small shipments to dealers and users, getting the production
run out of the garage faster. Similarly, the distributor collects
money from dealers and pays you with a single check. Don't
get too excited; you won't ship all 2000 copies at once. Dis
tributors might order 50 or 100 copies at a time to fill their
requests from local dealers.
You may also have to wait for your money- Distributors
often demand credit terms from you of 30 to 60 days, mean
ing your check arrives five to nine weeks after you ship the
product. Be warned: Developers love to swap horror stories
about distributors who do not pay on time. Insist on C.O.D.
payment instead. Of course, distributors balk at C.O.D. be
cause it affects their cash flow.
While the distribution method reduces your money has
sles, it also reduces your profit. Software passes through
many hands before it reaches the dealer, and everyone along
the way makes money. You, the developer, sell to distribu
tors, who sell to dealers and mail-order houses, who in turn
sell to users. A distributor typically buys software at 60 per
cent off the list price, so they pay $19.98 for your $49.95 prod
uct. Some distributors sell to other distributors for a small
percentage over their price. A US distributor might sell it to
a German distributor for about $25. Some mail order firms
buy direct from developers, which explains their low prices.
A local Amiga dealer pays about 50 or 60 percent of the
retail price, or about $30. Most dealers don't charge full retail
prices, so their profit is SI 3 to $20. From this raw income, they
must subtract their operating overhead.
For each copy sold, you take in about $15, while everyone
else gets about $15, too. Over the course of the lifetime of this
product, you'll get about 530,000 if you sell all 2000 copies.
You can use this to repay the initial investment and for your
first paycheck. Meanwhile, the bills for advertising, tele
phone, professional services, office supplies, and printing ar
rive in a steady stream. Because the size of the Amiga market
and the appeal of the product have placed a cap on our po
tential sales, Little Garage Software can't make more money
in volume without raising the product price, which could in
turn reduce sales.
BUSTLING OR BUSTED?
While this story had plenty of realistic detail, we also
waved our hands and minimized costs. Little Garage Soft
ware wasn't a slick operation. It had no full-color ads in mag
azines, no fancy colorful packaging, no plastic boxes for the
software. Frankly, it was a shoestring operation, and the soft
ware packaging looked cheesy. You can understand why
many small software companies are short-lived. High start
up and fixed costs can eat away quickly at a small investment
and force you back to a regular job.
The story of Little Garage Software shows why third-party
developers are the lifeblood of any computer company. The
entire chain of developers, distributors, and dealers collapses
if companies aren't profitable. If the Amiga market is to have
a professional image and professional software, customers
must be willing to pay this price. ■
John Foust and Harriet Maybeck Tolly are president and and vice-
president, respective!]/, of Syndesis Corporation, which bore a sus
picious resemblance to Little Garage Software at its inception. Con
tact them do The AmigaWorld Tech Journal, 80 Elm St.,
Peterborough, NH 03458.
44 April/May 1991
~
Step Up To The Podium!Admit it. You're an expert. You know how it works better than (almost) any
one. When you write code, you play by all the rules, yet your programs consis
tently out perform even those of the most wild-eyed ROM-jumping hacker. It's
been obvious to you for some time that you should sit down at the keyboard, fire
up your trusty text editor, and write an article explaining exactly how and why it
should be done your way.
If the above description seems to fit you to a T, perhaps we should be talking.
The AmigaWorld Tech Journal is looking for technical writers who have expertise in
one or more areas and have a burning desire to share that information with the
Amiga technical community. We need experts in all aspects of programming the
Amiga, from operating systems to graphics to the Exec. You can write in any lan
guage you like—C, Assembly, Modula II, or BASIC. Best of all, you can include as
much source code as you need, because all source and executable is supplied to
the reader on disk. We also need hardware maestro's who can explain—in thor
ough detail—the inner workings of such complex components as the Amiga's
chip set, expansion bus, and video slot. Don't forget algorithms either, we'll help
you pass on your theories and discoveries.
The AmigaWorld Tech Journal offers you an unparalled opportunity to reach the
Amiga's technical community with your ideas and code and to be paid for your
efforts as well. So, whatever your "it" is that you want to write about, The Tech
Journal is the place to publish it.
We encourage the curious to write for a complete set of authors guidelines and
welcome the eager to send hardcopies of their completed articles or one-page
proposals outlining the article and any accompanying code. Contact us at:
The AmigaWorld Tech Journal
80 Elm St.
Peterborough, NH 03458
603/924-0100, ext. 118
The AW Tech fan runt 45
Control Your Channels
Front p. 12
handler (not a server), register aO contains the base of the
custom chips, al is the IS_DATA (which points to the appro
priate channel's LoopSrruct's loopLength), and SysBase is in
a6. First, audiolnt( ) checks if bit 31 of loopLength is set. Be
cause this is always clear upon the first block-done interrupt,
audiolnt( ) does not turn the channel off—a good thing be
cause the oneShot portion just started playing.
If the wave has a looping portion, program control falls
through to 12, where the loop portion's location and length
are written. Note that I am doing this even as the oneShot is
starting to play, because the DMA has already copied the
oneShot location and length to the backup registers. 1 do not,
however, change the volume or period because the new val
ues would take effect upon the next data fetch. Note that not
only do I clear the interrupt (via intreq), which you should
always do, but I also disable the block-done interrupt (via
intena). This means that audiolnt will not be called again
when the DMA starts playing the looping portion. Instead,
the loop will repeat until I turn the channel off in main.
If the wave has no looping portion, the program branches
to 13 where it sets bit 31 of loopLength and does not disable
the interrupt. This means that audiolnt will be called again
when the oneShot portion finishes, at which time bit 31 of
loopLength will be set. The program then branches to 14
where it stops the channel. The net result is that it plays the
oneShot portion once, and then stops the channel. Other
wise, the DMA would continue looping the oneShot!
Note that in _main, I make two calls to PlayNote( ), once
to play a wave with oneShot and looping portions and once
to play a oneShot only. After I play the looped wave, I must
stop the wave's playback, either by playing another note on
this channel or calling StopChanf ). Ido the latter at label M7
in _main. Of course, you can play up to four waves simul
taneously by calling PIayNote( ) four times with different
channel numbers. Beyond this, PlayNote() will "steal" the
channels from previously playing waves. At label M10, I
make three calls to PlayNote( ) (each on a different channel)
so that I sound a major triad. Note how I use Transpose-
Period{ ) to get the pitches of the chord.
FURTHER IMPROVEMENTS
To increase efficiency, instead of calling Transpose-
Period( ) before each call to PlayNote( ), you could make
your own lookup table for each wave. Simply call Transpose-
Period( ) for each step of the scale, stuffing the returns into
an array of shorts, then use your step value to look up the
appropriate period. This eliminates the lengthy division in
TransposePeriod( ), either method is more efficient than the
audio device.
If you need to play sound effects for your application (typ
ically oneShots), then you can use PlayNote() as is, and it
will be much more efficient than using the audio device. If
you want to play musical passages, you should make a
higher level function that has a clock that tells you when you
should play and release each note at some tempo (when to
call PlayNote() and then StopChan( )). No matter which im
plementation you choose, it will be more efficient than using
the audio device. ■
Jeff Glatt is co-founder of and a principle programmer at dissi
dents, which specializes in music software. Write to him do The
AmigaWorld Tech Journal, 80 Elm St., Peterborough, NH 03458.
Amiga Device List
From p. 29
DF2: device-a 5>/rinch MS-DOS drive-and a RAD: (re
coverable RAM disk). Logical assigns to rename DFO:, DFL,
and RAM: also typically occur in a startup-sequence file; A:, B:,
and R: are often common choices for these.
As we have seen above, the DosLibrary, RootNode,
Doslnfo, and Devlnfo structures are all linked together ac
cording to the scheme shown in Figure 1.0. For that reason,
the program first declares four key structure pointer vari
ables in its global-data area. These point to specific instances
of the DosLibrary, RootNode, Doslnfo, and Devlnfo struc
tures; all tour pointers are initialized to NULL values.
Once the dos.library is successfully opened, the program
obtains pointers to each of the other three structures by read
ing appropriate pointers in each of these linked structures.
The program appropriately typecasts each pointer as it is as
signed to the global variables. Notice that Listing.l also uses
the dos.h include file BADDR (BCPL Address) macro to
change the rn_lnfo and di_Dev!nfo BPTR pointers to nor
mal C pointers.
Just as a matter of curiousity, Listing.l prints the current
addresses of these four structures. Because the Amiga has
only one fixed address and these structures are allocated at
run time, these addresses may change each time you execute
the program, especially if your RAM contents have changed
since you last executed it.
The next phase of the program consists of a for loop that
looks at the linked list of Devlnfo structures. Here it prints
key information about all the devices (real, logical, and disk
volume) that are currently linked into your system. First, it
prints the device name (the dvi_Name parameter) and then
the device node type (the dvi_Type parameter). In this for
loop the program uses the arp.library BtoCStr function. The
BtoCStr changes a BCPL language BSTR string to a C string.
If you look at the above definition of the Devlnfo structure,
you will see that the dvL-Handler pointer is defined as a
BSTR pointer. To accommodate this situation, you define a
dummy holding string buffer called cString for placing con
verted C strings. Then in the printf statement where the pro
gram prints the dvi_Handler pointer, you reference that C
string directly.
The ARP library BtoCStr function returns the number of
characters in the resulting C string. Therefore, you print ap
propriate messages for two different cases to indicate what
the presence or absence of a dvi Handler string really
means. (As you saw above, some DOS devices have no han
dler file in the L: directory.)
The result of this printing loop is a long list of grouped
items, each group representing an AmigaDOS device node
currently in your system. You will see type 0 (real device)
entries for DFO:, DF1:, RAM:, SER:, PAR:, PRT:, CON:, and
RAW:; type 1 (logical directory device name) entries for SYS:,
EVN:, S:, L:, C:, FONTS:, devs:, and libs:; and type 2 (volume)
entries for the disk volume names assigned to the disks cur
rently in DFO:, DF1:, and any other drives in your system.
You can extend the program to determine other key values
for all the DOS devices in your system, then use the results
to capitalize more fully on you system's resources. ■
Eugene Moitimore is a developer and the author of Sybex's
Amiga Programmer's Handbook, Volumes I and II. Write to
him do The AmigaWorld Tech Journal, 80 Elm St., Peterbor
ough, NH 03458.
46 April/May 1991
Shared Libraries
From p. 31
~
~
##1ibid Amiga World TJ lib (ver 1.0)
##bias 30 'first function is always at an offset of -30 from lib base
*Here are all of the lib functions callable by an application
*They all return doubles
##ret double
Mag( real, imaj )
Ang( real, imaj }
Real{ mag, ang )
lmaj( mag, ang )
////end
This one file holds virtually everything you need to de
scribe your library (and update it in the future). Each spe
cialized item has its own command. Of particular interest are
the#£init and-?5#expu commands that precede the names of
the initialization and expunge routines. If required, com
mands are available for the previously mentioned open and
close routines (##open,##clos).
COMPILE, LINK, AND GLUE
UsingManx 5.0 from the CLLyou make the library as follows:
LibTool cmho glue.asm AWMb.fd
This creates the library startup code (AWlib.src) using C-style
syntax (it adds an underscore before the function names), the
C header file (AWlib.h) for the applications, and a C appli
cation glue file (glue.asm) that will be assembled and linked
with the application.
Next, the statement:
as -cd -o LibStart.o AWlib.src
assembles the library startup module. Because I am using
large code and data, I need not worry about saving register
A4, as I would with the small model.
Again using the large model, I compile the library code:
cc -mcdOb -rf AWIib.c
The command suppresses the standard Manx startup (.be
gin), and uses fast floating-point math.
Finally, I create the library by linking together its compo
nents.
In -o libs:AW.IIbrary LibStart.o AW Lib.o -Imfl -Id
LibStart.o always must be the first object module in the list.
To use the library, compile and link your application in the
standard manner. If you are using glue files (as I am), assem
ble glue.asm, and then link it with the application program.
The example program AWlib_app.c, simply opens the library
and calls each of the functions.
For information on using LibTool with the SAS compiler and
assembly development systems, or to create BASIC .bmap files
and construct devices, see the on-disk documentation and ex
amples. Whether you use them to house frequently used rou
tines, divide a large program into a series of libraries, or share
functions with friends, libaries will make your programming
easier and your programs tighter. ■
Jim Fiore is a co-founder ofand programmer at dissidents. He has
written for computer and music publications ami is currently writing
an electrical engineering text book. Contact him c/o The Amiga-
World Tech journal, 80 Elm St., Peterborough, NH 03458, or on
BlXasjfiore.
The Fast Floppy System
From p. 33
While we do not see these labels, the drive does, and uses them
for file recovery. In both the old and new file systems, the file-
list block holds the list of blocks that the file uses.
Our file-recovery programs can still reclaim files as well as
ever, but they must work a bit harder than before. Program
mers who write file-recovery programs need to allow for the
fact that people may use disks formatted under both systems.
A recovery program must be able to determine which kind
of disk it is reading and supply appropriate branches to the
routines needed for each kind of disk.
HACK TO THE FUTURE
The FFS offers substantial improvements over the Amiga's
original system. Future changes to the file system will give
us much faster access than we now have. Longer file blocks
will require fewer reads and writes and less head seeking,
which will also make the system faster. With the advent of
longer file blocks, we will also see hash tables grow longer
than the current 72 slots. The hashing algorithm can then be
changed to allow for the bigger tables, and there will be far
fewer hash-chain collisions to impede finding files.
The foundation for these changes is already in place. Using
such an improved file system will not require the rewriting
of programs, but merely that programs address the file sys
tem in the established and approved manner. ■
Betty Clay, a sysop on CompuServe's Amiga Forum (76702,337)
writes for several Amiga publications. Write to her c/o The Amiga-
World Tech Journal, SO Elm St., Peterborough, NH 03458.
Perfect Joystick
From p. 35
An equivalent to this is:
lea Y,aO
lea X,ai
move.w (a0,dO.w),d1
move.w (a1,d0.w),d0
rts
Y dew 0,1,1,0,-1.0,0,-1.-1.0,0
X dew 0,0,1,1,0,0,0,1,-1,0,0,0,-1,-1
By noting the relationship between Y and X (X = Y + 22),
you can eliminate one of the LEA instructions, as shown in
the first part of this example. You find the vertical position
by looking at Y + DO and the horizontal by looking at X +
DO (which, because the horizontal table begins 22 bytes after
the vertical, is 22 +Y + D0). Note that both sections look up
the vertical value before the horizontal. If I had arranged
them in the other order I would have corrupted the value in
DO (the index).
While you probably do not have the time to fine-tune all
of your routines, try to occasionally exhaust the possibilities
in the search of perfection. The final code I arrived at is quite
efficient (see Listing.2 in the the accompanying disk's An
derson directory). It comes close to being the best way—in
terms of speed and code size—to read the joysticks. ■
Rhett Anderson is co-author of Mapping the Amiga and co-
founder of Neandersoft Inc., a game development company. Write
to him c/o The AmigaWorld Tech Journal, 80 Elm St., Peterbor
ough, NH 03458.
The AW Tech Journal 47
LETTERSFlames, suggestions, and cheers from readers.
APPLAUSE .
Your idea to create The AmigaWorld
Tech journal is great! The demise of
Transactor was very unfortunate —I
bought a Commodore 64 so that I could
justify reading the original magazine.
For those of us that write software for
the Amiga now (whether profession
ally or for personal enjoyment), a tech
nical journal is extremely important.
Even for those who don't program,
there are a great many technical issues
that need to be covered. Enclosing a
disk containing program examples,
software tools, program demos, late
breaking information, and so forth is
also a very good idea. I can't wait!
Richard A. Bilonick
Pittsburgh, Pennsylvania
PROPOSALS FOR SOFTWARE
I have a few ideas for developers.
Software should follow certain behav
ior standards. For example, if the
Amiga is a GUI system, then all soft
ware should load from the Work
bench and have icons, including
games. As a further step, get rid of the
nonstandard disk operating systems
found on some game disks. In the
IBM and Mac worlds 99.9% of the
software can be put on hard drives.
Why shouldn't every application and
game on the Amiga include a batch
file for copying programs to a hard
drive? This brings up another matter;
get rid of on-disk copy protection. I
favor manual protection, instead.
Chris Browne
Maple Valley, Washington
AND THE JOURNAL
Please do not ignore the system
hardware in your new magazine. The
hardware is essentially the Amiga's
only feature that distinguishes it from
other computers. Detailed explana
tions of how the hardware functions
and various hacks make for interest
ing reading.
I also suggest you feature a "clever
algorithm of the month" in your mag
azine. Helping Amiga owners become
better programmers instead of game
players will help protect the invest
ment we've all made in this machine.
Dan Larson
Shillington, Pennsylvania
PLUS A WARNING
Congratulations on your decision to
provide more in-depth technical infor
mation to the Amiga community. I
know from my own struggles that
getting technical details is time con
suming and expensive. After several
months of floundering around trying
to get information, I discovered what
a great bargain the Commodore De
veloper's program is. Whatever you
do, do not simply rehash the informa
tion that is in AmigaMail. Your techni
cal articles should contain "fresh"
information that complements what
CATS presents in theirs. Please don't
misunderstand, I like your idea! A
year ago, it would have saved me
considerable time and aggravation. I
won't pay twice for the same articles,
however.
Valorie Jackson King
Bowie, Maryland
DISK DISTRESS
You have stated The AmigaWorld
Tech journal will be sold with a disk
and implied it will not be available
without one. I hope you reconsider
this stand and provide a diskless ver
sion. While I buy almost every Amiga
magazine, I do not purchase maga
zines with disks. As long as the source
to programming articles is provided
within the text I am willing and able
to input the examples that 1 need into
my editor.
Bob Lockie
Bulington, Ontario
As a former reader of Transactor, I
was pleasantly surprised to read your
announcement of The AmigaWorld Tech
journal. I am disappointed, however,
that you have chosen to automatically
bundle it with software. Please con
sider offering your readers the option
of buying it without the disk. Even if
your magazine is very good and a
reader has extremely eclectic interests,
it is unlikely that more than one or
two articles in each issue will be of
lasting interest. That means that much
of the hefty purchase price will be
wasted on programs of little or no
value for that particular reader.
Gary A. Gruenhagen
Sierra Vista, Arizona
While I can understand your concerns,
we decided to include a disk with every is
sue to eniiance the value of The Tech
Journal. By relegating each article's asso
ciated source code to disk, we have room in
print for more articles and articles on top
ics that require longer listings than could
be printed. As we are also providing a
sampling of utilities, libraries, and even a
compiler from time to time on the disk, I
am confident you'll get your money's
worth.
TELL US MORE
How did you like our first issue? Any
suggestions for the next? What are your
thoughts on the state of Amiga develop
ment? Do you have a technical question
that you can't find the answer to? Let us
know'. Drop a note to Letters to the Editor,
The AmigaWorld Tech Journal, 80 Elm
St., Peterborough, NH 03458. Letters may
be edited for space and clarity. ■
48 April/May 1991
o
SUBSCRIPTION OFFER
AmigaWorld
I enter my one-year (6 bi-monthly
• issues, plus 6 invaluable disks)
Charter Subscription to The AmigaWorld Tech Journal A(IJ[1.S1
for ihe special price of S59.95. That's a savings of
S35.75 off the single copy price. If at any time I'm not Cil>
saiisfied with The AmigaWorld Tech Journal, I'm □ Check/Money order enclosed
entitled to receive a full refund — no questions asked.Charge my: C Mastercard C AMEX □ Visa
Canada mm! Mexico S7J W Foreign Surfire SKJ.95. Foreign A.rmi
Payment required in L1 S. fundi drawn on U S bank Avulihlc Much 15
Or call 800-343-0728 1
-Zip
TS41I
□ Discover
. Etp
Signalme
603-924-0100 for immediate service.
I-MONTHLY ISSUES 6 INVALUABLE DISKS
BUSINESS REPLY MAILFIRST-CLASS MAIL PERMIT #73 PETERBOROUGH. NH
POSTAGE WILL BE PAID BY ADDRESSEE
The AmigaWorld Tech Journal
P.O. Box 802
Peterborough, NH 03458-9971
NO POSTAGE
NECESSARY
IF MAILED
IN THE
UNITED STATES
The AmigaWorld
TECH TOURNAU~
21 ■ CO! Enter my one-year(6 bi-monthly issues, plus 6 invaluable
disks) Charter Subscription to The
AmigaWorld Tech Journal for the
special price of $59.95. That's a
savings of $35.75 off the single copy
price. If at any time I'm not satisfied
with The AmigaWorld Tech Journal,
I'm entitled to receive a full refund
— no questions asked.
Name
Address
Clfy State .Zip.
TL41IQ Check /Money oider enclosed
Charge my: U MasterCard 3 Visa uAmex Q Discover
Account* _£xp.
Signature
Canada ana Merico SM.M. Foreign Surface $84.95. Foreign Airmail $9M5.
Payment requ»ed *i U-S- Funds aawri on U.S Bonk. AvoftaOe Uotcn 15
Or call 800-343-0728 ff 603-924-0100 for immediate service.
BUSINESS REPLY MAILFIRST-CLASS MAIL PERMIT NO. 73 PETERBOROUGH. NH
POSTAGE WILL BE PAID BY ADDRESSEE
AmigaWorld Tech Journal
P.O. Box 802
Peterborough, NH 03458-9971
NO POSTAGE
NECESSARY
IF MAILED
IN THE
UNITED
STATES
~Sapphire 68020 / 68881 Accelerator
Fits in the Amiga 1000, Amiga 500, and the Amiga 2000/WFits snugly in the 68000 socket.
Easy installation - Included is a disk with installation
instructions, pictures, and public domain benchmark software.
Also included is a static safty strap and static safty instructions
that apply to all computer hardware. Factory installed 12 MHz
32-bit 68020 CPU and a factory installed 12 MHz 68881 FPU.
Speed increases of up to 2.4 times faster in standard interger
processing, and up to 3.2 times faster in floating point. Small
compact size makes the Sapphire the smallest accelerator yet!
Only 3 1/8" x 4 1/4" x 1/2" total size. Not a psucdo accelerator,
but a true 32-bit accelerator card using true 32-bit processors.
A full one year factory warranty. Retail Price S399.95
Workbench Management System**.^The Workbench Management System {WMS) is a
revolutionary idea in sonware for the Amiga! WMS is
based on a button concept where a single click of the mouse
button will launch your applications. Buttons can be
assigned to any program on a hard disk, floppy, or
network. WMS allows you to launch as many programs as
your memory will allow for as fast as you can click (he
mouse. WMS also includes eight built in programs.
• Memo-ed: A text editor.
• Calendar: A calendar that you can add daily appointmen ts to.
• Remind: Is built into the calendar and can be set up to remind
you upon boot up every day.
• Telemate: A phone address book with dail capibiltiy.
• Squeezebox: Archiving with the compression programs made
simple. And More! Retail Price S49.95
MRBackup ProfessionalMRBackup Professional is the first full featured backup system
for the Amiga utilizing the fiill potential or the Amiga! With over
60 built in ARexx™ commands, MRBackup Professional gives the
user the ability to reach beyond standard backup options. This is
the first full featured hard drive backup system that has floppy
and SCSI streaming tape capibilities.
• Will backup to floppy or SCSI streaming tape - Fully tested wiih
Commodore, Supra, Xcicc, CLld, Trumpcard, and GVP conlollers.
• Full ARexx™ Integration - Over 60 usable commands.
• Utilizes the option to use standard AmigaDOS or Fasldisk Formal.
• Has a user selectable file compression - selectable up to 16-bit.
• Uses full AmigaDOS inluition for ease of use.
• Roppy users can use up to 4 floppys.
• MRBackup is compatible with AmigaDOS versions 1.3 and 2.0
Retail Price 54.95
^ Teachers ToolkitTeachers Tool Kit is a complete lesson planner and grade
book written by a teacher for the teacher. Teachers Tool
Kit allows the instructor to plan (he lessons for the class
and track the advancement of each student sepcratly, or
each different class as a whole. Some of (he built in
features of Teachers Tool Kit Are:
• The ability to store and print graphs, reports, grade book and
student information.
• The ability to assign each student a unique ID number.
• The ability to create general subject areas that would have
sepcrate lessons, tests, quizs, homework, and project that
need to be completed by indivdual calsses.
Retail Price S49.95
RxToolsRxTools is an object oriented user interface builder, which extends
the capabilities of ARexx™. It connects the inatc texual interface
of ARexx1" with the user interface of the Amiga, more commonly
known as intuition. Intution in its raw form is a difficult
programming enviroment. RxTools converts intuition into a
manageable system with minimal loss of flexibility. Furthermore,
it makes it directly accessible in this form to the ARexx™
programmer. With the bult in text editor RxTools provides a
complete development enviroment, which may be the best
available for the Amiga, in terms of overall capability and ease of
use. RxTools is a function host program, which when run, stays in
the background and allows for the use of the future RxTools
extension set to be utilized in ARexx™ scripts. RxTools provides
intuition capibility including windows, gadgets, requestors, andmore.
Retail Price 54.95
TTR Development, Inc.1120 Gammon Ln.
Madison, WI 53719
(608) 277-8071
United States, European, Australian Sales and
Distribution
Brigade
A new revolution in gaming software for the Amiga. Most war
games work on a turn by turn basis. Brigade takes you one step
doser to reality by adding in real time action. Brigade offers
excitment not found in other war game simulators. If you do not
pay attention or you leave without pausing the game the computer
will continue with its war plans and you could lose the game. You
may take a break but the enemy never does.
• Real-Time game play.
• Built in scenario/campaign editor - you can create or modify any
vehicle, weapon, aircraft, map, and more!
• Oversized map to allow for larger than one screen play.
• Full digitized sound.
• Animation of weapons firing.
• Full control of units, their orders, and missions.
• Special Limited Time Offer-Desert Shield Data Disk Included!! •
Retail Price S44.95
Pre'spect Technics, Inc.P.O. Box 670, Station 'H>
Montreal, Quebec H3G 2M6
(514) 954-1483
Canadian & South American Sales andDistribution
TAKE THIS JOB AND LOVE IT!The fastest growing video technology
company in the world is looking for technicalsupport specialists- We're looking for the kindof person that enjoys solving problems. If you
have the unique ability to; hear a problem, askthe right questions, analyze the answers, and
then provide a perfect solution, you belong
with NewTek. You'll be a key member of thebest support team in the business. Best of all,
you'll be working for a company that has an
intense commitment to serving its customers.
We're looking for rare individuals with asmany of the following qualities as possible:
• Excellent written and verbal communication
skills
• Experience in video production and editing
• Knowledge of 3D animation and computer
graphics
• Knowledge of Amiga software and peripherals• Experience with Digi-View and Digi-Paint
• Experience with the Video Toaster
• Work experience in the technical support field
The Video Toaster is changing the way
the world thinks about video production. TheToaster is being used everywhere from net
works to cable stations and our users range
from rock stars to wedding videographers.
Helping producers, artists, and video makers
use this powerful tool to revolutionize videois an exciting and rewarding career. If you're
ready to make a change for the better callKiki Stockhammer at 913-354-1146.
215 S.E. Eighth St.
Topeka. KS 66603
913-354-1146
FAX: 913-354-1584
NewTekINCORPORATED