-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

                   QB CULT MAGAZINE - Issue 3 - May 2000             

                   -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
                          Editor: Matthew R.Knight

                       Email: horizonsqb@hotmail.com
             Design and HTML coding: Merlin of Master Creating

                       Email: mail@master-creating.de

                     Website: http://master-creating.de            
              QBCM archive, latest news, and discussion forum: 
                         http://picksoft.zext.net
             QBCM is also available on the following host sites:
                         http://alienqb.cjb.net

                         http://aurskogcity.8m.com

                         http://master-creating.de

                         http://www.neozones.com/geoshock

                         http://neozones.tekscode.com

                         http://qbversions.cjb.net
Much thanks to the owners of the above sites for hosting QBCM. If you are 

hosting QBCM on your site, and it is not listed above then please contact me

at horizonsqb@hotmail.com so that it can be added.
We need QBCM to be available on as many Qbasic related websites as possible.

That way ALL Qbasic coders can benefit from it. If you have a website 

dedicated to Qbasic then please become a host of QBCM too! 
All you have to do to become a host is email me telling me the URL of your

site, and then I'll send you the new issues every month, and your site will

be listed on the QBCM host list!
Copyright (C), 2000, All rights reserved worldwide. QB Cult Magazine is the 

exclusive property and copyright of Horizons Interactive Entertainment. The

HTML coding and magazine design is the exclusive property and copyright of

Master Creating. 
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

                                 FOREWORD

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Welcome to the third issue of Qbasic's #1 magazine!
You'll recall that last issue was really huge and very different from the 

issue before it, well, this month see's some big changes once again in 

QB Cult Magazine! Merlin of Master Creating is now doing the design and 

HTML coding for QBCM and as you can see, he is doing a much better job of

this than I did with last issue! Thanks again Merlin :)
QBCM now has an official archive and discussion forum! Much thanks goes to

Chris Charabaruk for this. It is greatly appreciated. Be sure to check this

out at http://picksoft.zext.net in the QBCM section.
Many of you probably heard the rumours early last month that QBCM is closing

down. This is NOT going to happen. QBCM will continue for a very, very long

time I can assure you. Certain unforseen circumstances last month almost

brought about an end to QBCM. These have fortunately been resolved. Once

again, I will NOT be stopping QBCM, and can't forsee doing so.
As far as errors in the last issue are concerned, it appears that there was

only one. In my review of Mysterious Song, I awarded the game 90%. At the

time of writing the review I had played very little of the game. However,

I have since completed it, and I must say that the game is far better than

I originally thought. I was highly impressed with Mysterious Song at the

time of reviewing it, however, having now played the entire game, it has

become apparent that the game deserves far more credit than I gave it. It

would be a crime for it to get anything less than 100%. It is not often that

a game leaves such an impression on me...however, Mysterious Song is more

than just a game. It has a wonderfull and touching story, behind which are

some very original and intelligent philosophies. In addition to that, the

game boasts stunning visuals, beautifull background music, and gripping

gameplay. Everything in MS has been seemlessly integrated and moulded

with such perfection - it's almost magical! So, let me now take this

oppertunity to correct this mistake and give Mysterious Song the rating it

truly deserves - 100%. My sincere apologies go to Darkness Ethereal for not

giving MS the review it deserved in the first place.
The rate at which QBCM has grown never ceases to amaze me. What started out

as only a small text-based magazine two months ago, has grown into the

biggest and quite possibly the best Qbasic magazine our community has ever

seen. Every time I check my email I have loads of emails from fans of QBCM,

which is very nice to see. Unfortunately however, few people are actually

contributing towards QBCM. I simply do not have the time to write as many

articles for QBCM as I'd like, so if you want QBCM to be really big and

interesting, then it's really up to you. I can't write more than 3 articles

per issue. I'd like to have at least 6 articles every issue, but that is far

more than I can write in a month. So PLEASE CONTRIBUTE SOME ARTICLES PEOPLE!

Please send all articles to me at horizonsqb@hotmail.com
The phenomenal growth of QBCM, not only in size but also in quality, is

by no means due to my efforts alone. I would like to take this oppertunity

to thank the many people who have contributed in some way or other to

QB Cult Magazine. Your efforts and support are greatly appreciated.
Even more amazing than the growth of QBCM is the growth in the number of 

quality Qbasic programs. What seemed impossible in the language only a year

ago is a reality today. Needless to say, this is due to the sudden surge in

the amount of libs over the past year, or so. Keep coding everyone...from 

now on QuickBASIC is the only language we need! POWER TO QB!!! ^_^
Hope ya like this issue! Enjoy! ^_^
-Matthew River Knight

 Horizons Interactive Entertainment 
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

                              YOUR LETTERS

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
QBCM takes a lot of time and work to complete every month, and I am thus

always delighted to hear from its readership. Please write to QBCM at

horizonsqb@hotmail.com with your comments and suggestions, or basically

anything you have on your mind to do with Qbasic ^_^
All of last months letters were lost due to unforseen circumstances. My

sincere apologies go to all QBCM readers for this. 
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

                          ASK QB CULT MAGAZINE

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Don't you just hate it when you are really stuck on something in Qbasic and

no matter how hard you try you just can't figure it out? Doesn't it drive

you completely nuts? Yep, I thought so, so that's why I included this

section in the mag for ya! If you get stuck on anything in Qbasic, just send

an email to me at horizonsqb@hotmail.com and you'll get a reply within three

days. In addition to that, your problem will be printed here in QBCM, along

with my reply, so it can help other coders too! ^_^
All of last months questions were lost due to unforseen circumstances. My

sincere apologies go to all QBCM readers for this. 
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

                   BUZZ - NEWS FROM AROUND THE QB WORLD

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
* April was a very bad month for Nekrophidius. Amongst other things, a great

  deal of his work was lost due to a virus. Consequently, Nek soon announced

  his retirement from, not only the QB world, but programming in general.

  Fortunately, Nek later changed his mind. Almost all work on most of his

  projects has been lost due to the virus. The only project untouched by the

  virus was Killers. Nek has decided to start both QuickPower and Wrath of

  Sona from scratch! We wish Nek the very best of luck in getting these

  projects up and running again. Nek is probably one of the most intelligent

  coders in the Qmunity today, and also one of the most helpfull, having

  helped countless coders with their coding problems. It's sad that such a

  cool guy became the victim of the stupidity that exists in the world

  today - people who write viruses think they're being clever...heh,

  BULLS**T! They are just showing how damn stupid they are, being incapable

  of thinking of something constructive to do.
* Tsugumo recently posted the following article on the Darkness Ethereal

  discussion board: 
  Bear with me, this is long winded. It also might not describe the board

  it's posted on, but check it out and see what you think.  
  After visiting boards around the net, FrozenEmu and myself have found that

  basically WWWBoards suck right now. They generally have only a few people

  that visit, and even less posts that even relate to game development. The

  boards that are still active (except for a few) are active only because of

  people posting new flames and such. This is usually because the

  maintainer of the board doesn't give a crap and lets idiots run free.
  From going around, we've found that there are a lot of people who want to

  get back to game discussion, the way things used to be a few years ago...

  So what we want to do is start up a central WWWBoard, not attatched to

  anyone's game/site, where everyone can meet.
  The benefits of a board like this, is imagine if everyone went to one

  place to release and find information. For the people who want to know

  what's going on, they need only stop at one board, rather than search

  through the spam at 30 different boards around the net. For the people who

  want to show off new demos, screenshots, or whatever, they only have to

  post on one board for a ton of people to see it and give feedback.
  The board will be moderated by FrozenEmu and myself, and we will delete

  threads that get way out of hand, spammers, etc. and ban people that need

  banning. Like many others, we want a WWWBoard where we can go to discuss

  game related stuff without the worry of being flamed or being faced with

  tons of idiots.
  Anyway, we're calling it the Game Developer's Refuge:

  (http://www.swoo.net/gdr/index.pl) and we're posting this to whatever

  WWWBoards we know of...Please spread the URL around so we can get a

  "community" together like the old days. You can read more about our

  philosophy and rules at http://www.swoo.net/gdr/rules.htm because believe

  it or not, this is the "short" version, heheh... 
  We're also working on a good design, graphical and game-ish looking and

  such, but it's not ready yet and we want to see if we can draw many

  people to this idea first.
  So for a greater communication level throughout the programming world,

  please take part."
* There's quite a bit of news from Darkness Ethereal. Firstly, serious work

  has started on Dark Crown. DarkDread has announced that he hopes to have

  a tech demo up within the next month or so. 
  On the Distant Promises side of things...well, there hasn't been much said

  about that in ages! DarkDread has however announced that he still intends

  to complete the project. Nekrophidius is still composing some awesome

  tunes for it. DD is also considering re-coding the game, so it might take

  a bit longer than originally anticipated for the game to come out. One more

  demo is planned to come out, before the final release. ^_^
  Oh no! My favoutite upcoming Darkness Ethereal game, Eternal Frost, has

  hit the QB dustbin. =( This has been done, as DarkDread said, because he

  simply doesn't have enough time to make this game of the quality he'd

  like it to be.
  But wait...DarkDread has announced that Mysterious Song 2 will be made!

  It's a long time off, but this is very good news indeed! :) The story

  will continue where the first one left off...hmm...this is good...I still

  would like to know what happened to...ehm, I don't want to give away the

  story to those who haven't finished episode 1...so never mind ;)
  Visit the Darkness Ethereal website at http://welcome.to/DarknessEthereal
* Jaws V soft, best known for their MiniRPG series, have just released

  MiniRPG1 Boardgame! This game totally rocks!!! It is available for

  download at http://members.aol.com/changev/index.htm
* The new game engine behind Magnet Entertainment's RPG, Dark Aura, is

  pretty much complete. I saw a demo of it, and it's certainly much better

  than the old engine. Check out the Magnet Entertainment website at

  http://www.geocities.com/Magnetent
* The second demo of Badjas (of Future Software)'s 3d engine has been

  released. A lot of new stuff has been added to the demo, and it's also

  running at a MUCH better pace. Visit Future Software's awesome webiste

  at http://www.qb45.com  
* Zed (aka Kristoffer Ström) is busy on a console style RPG called Dark

  Fall. The game boasts many new and original features, an intelligent

  and well-conceived story, and high quality visuals and sound. Good luck

  on this game Zed! We'll keep you posted on the latest developments

  regarding this project as it arrives. 
* Will Moores is busy on a 13h graphics library called ZipLib. It's still

  in the early stages of production, however, I saw an early demo of it

  and it ran at a good pace. Good luck on this project Will! More news on

  this will follow, as it arrives.
* AlienQB is busy on a pretty rockin' new SVGA game called Infernal Forces!

  Find out everything you could possibly want to know about this cool new

  project at http://alienqb.cjb.net
* Dark Ages II, demo 9 has been released! Go check it out RIGHT NOW!!! You

  can download it from http://www.tcnj.edu/~hoopman2
* CarterSoft has released a cool new 32 bit BASIC variant called Novascript.

  Check out this month's review to see if it's da bomb or a bomb! You can

  get Novascript from http://www.cole_carter.tripod.com/novascript1.zip
* Gabriel Fernandez has released a very fast, 90% QB compatible compiler

  that works in pmode!!! It's called GABASIC and you get get it from

  http://gab_soft.tripod.com. The compiler still needs a bit of work, but

  it looks to be the one to watch.
* Phat Kids has returned to the QB scene. They dissapeared several months

  ago, but it was recently announced at the Darkness Ethereal discussion

  board that they're back and will be completing Kids of Karendow as

  planned! Yay!!! ^_^
That's all the news we got for you this issue. Please send any news or

rumours to us at horizonsqb@hotmail.com 
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

             OBJECT ORIENTED BASIC - Possibility or Pipe Dream?

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Writer: Unknown
TABLE OF CONTENTS
1.0 Introduction

1.1 Key Terminology and Concepts

2.0 BASIC-Specific Considerations of Object Paradigm Implementation

2.1 Standardization of Terms in Object Oriented BASIC

2.2 An Introduction to Advanced Topics in OOP

3.0 Closing Notes

1.0     Introduction
BASIC has evolved from the time-sharing "Beast of Dartmouth" into a

powerful, structured language fit for the programming needs of the

nineties.  Despite this evolution, however, major software compiler

developers have failed to introduce object oriented extensions into

the language.
This article will explore some possible extensions to modern

BASIC that would truly expand the language.  Since, because of its

nature, this article will use a speculative approach, the reader

should bear in mind that no particular implementation is being

suggested as the "best" way to bring object-orientation to

BASIC.  Moreover, some BASIC programmers may feel that certain low

level features such as in-line assembler and more diverse data

types should be introduced into the BASIC language before object-

orientation is even considered.  These readers should remember the

theoretical nature of this discussion, and leave all such

preferences out of the exploration at hand.

1.1     Key Terminology and Concepts
First, I must define some key terms and concepts.  My use of the generic

term BASIC (Beginner's All-purpose Symbolic Instruction Code) will,

unless otherwise stated, refer to the Microsoft QuickBASIC v4.5 dialect

of BASIC, since this represents a widely accepted implemenation of

modern, structured BASIC.  The term OOP (Object Oriented Programming)

will be used to refer to those programming practices that rely on the

object paradigm.  Although the terminology differs from compiler to

compiler, the object oriented paradigm is considered by modern usage to

intrinsically encompass the following concepts, to be defined later:
    1.  Encapsulation

    2.  Inheritence

    3.  Polymorphism

    4.  Overloading
Therefore, when I say that a given concept is "object oriented" I

specifically mean that it involves the above four concepts.

Other important terms that cannot be ignored in any discussion of OOP,

due to their repeated use in the discussion of such are:
    5.  Class

    6.  Method (or Member Function)

    7.  Object (or Class Instance)

    8.  Information or Data Hiding
Not able to decide which term to define first, I will begin with a

general overview fo the underlying philosophy of OOP.
In classical structured programming, data and code are considered

separate entities.  Code manipulates data.  Data fuels code.  For

example, wanting to implement a graphics font engine, a classical

BASIC programmer might read a list of DATA statements into a globally

accessible array, and then have a series of globally accessible

SUBPROGRAMS manipulate those raster data on the screen in such a

way as to produce the desired visual effect.  The problem with this

approach is that both the data and the related code are equally

accessible, and they are only loosely cohesive.  Wanting to enhance

code written by a colleague, a second programmer will encounter

data structures that he should neither modify nor even poll, but

that may not always be possible.  Having modified an essential

data structure, the second programmer may introduce errors

into the whole underlying logic of the system.
For instance, suppose the original programmer had defined the

font data structure thus:
    TYPE FontDataType

        FontName AS STRING * 12

        FontPointSize AS INTEGER

        RasterDataPtr AS LONG

    END TYPE
Now, looking at this, Programmer Two decides that he can avoid a

FUNCTION call to funGetFontPointSize() by just reading the value of

Font.FontPointSize directly.  Programmer Two alters his code to

access this variable directly, and in doing so, avoids what he

considers costly calls to funGetFontPointSize().  He is

promoted to another department (presumably for having sped up the

code of his predecessor).  Enter Programmer Three.  Quite within

his bounds, he discovers that point size is never greater than 255,

and so redefines the whole structure to account for this, thereby

reducing overall memory consumption by one byte:
    TYPE FontDataType

        FontName AS STRING * 12

        FontPointSize AS STRING * 1

        RasterDataPtr AS LONG

    END TYPE
Of course, being conscientious, he modifies funGetFontPointSize()

to account for this innovation.  He compiles the program.  It crashes.

Why?  Because, this is now an illegal statement:
    Font.FontPointSize = 12
What to do?  He must use his search and replace to go through the

entire program and change all such instances to:
    Font.FontPointSize = CHR$(12)
Or, he can forget his alterations altogether.
In BASIC, there is no INFORMATION HIDING that would prevent such

problems from occuring.  Since FontPointSize is a public member

of FontDataType, Programmer Two was well within his rights to do

as he saw fit as far as accessing it.  Had the original programmer

had an object oriented BASIC, however, he could have prevented the

entire problem with little difficulty by making FontPointSize a

PRIVATE data member of the CLASS font.  This might have looked

similar to this:
    CLASS FontClass

        FontName AS PUBLIC STRING * 12

        FontPointSize AS PRIVATE INTEGER

        RasterDataPtr AS PRIVATE LONG

        funGetFontPointSize AS PUBLIC FUNCTION

        subSetFontPointSize AS PUBLIC SUB

    END CLASS
    DIM Font AS FontClass
[Please bear with the strange new syntax, since it will be covered

in more detail in section 2.0.]
Now, the only way to access Font.FontPointSize is indirectly.  This

would NOT work, since this data member is now PRIVATE:
    Font.FontPointSize = 12
This, then, would be the ONLY way to achieve such a thing:
    Font.subSetFontPointSize 12
In the above example, the item Font is what is called a CLASS INSTANCE.

That is to say, Font is "an instance of the class FontClass." This is

what is commonly called an OBJECT, and it is from this that we arrive at

the phrase "object oriented" programming.
Now, when Programmer Two comes along, he CANNOT pull off his stunt,

and he is not promoted to another department.  Programmer Three comes

along, and sees room for improvement and redefines the class thus:
    CLASS FontClass

        FontName AS PUBLIC STRING * 12

        FontPointSize AS PRIVATE STRING * 1

        RasterDataPtr AS PRIVATE LONG

        funGetFontPointSize AS PUBLIC FUNCTION

        subSetFontPointSize AS PUBLIC SUB

    END CLASS
Since all calls to change FontPointSize are through the centralized

subSetFontPointSize, Programmer Three just modifies that a bit, and

earns himself a nice raise in salary for shaving a byte off the

memory requirements of the structure.
Consider the above example.  The data are:
    1. FontName

    2. FontPointSize
The code portions (called MEMBER FUNCTIONS or METHODS, since they

are "methods of acting upon or accessing" the data) are:
    1. funGetFontPointSize

    2. subSetFontPointSize
Since it is unlikely that subSetFontPointSize will ever be needed for

anything other than the setting of FontPointSize, it makes sense to

bind the code to the data it works with.  This binding is called

ENCAPSULATION.
Having examined these more essential terms, there is the issue of

OVERLOADING.  Although not object oriented in the strictest sense,

it does aid in generalizing classes to an extent that they can

operate upon different types of data.
Consider the following:
    subQuickSort A%()
Now, in classical BASIC programming, if we wanted to sort anything

other than INTEGER arrays, we would have to write another SUBPROGRAM

and modify the algorithm to account for this new data type.  This

SUBPROGRAM would have to be named something other than subQuickSort.

For example:
    subQuickSortSTR A$()
might be used for STRING arrays, and
    subQuickSortLONG A&()
might be used for LONG INTEGER arrays.  And, of course, should a

programmer ever want to sort a user-defined TYPE array:
    subQuickSortUserTYPE UserArray()
would be the only way to do it.
But, consider the above.  All of these routines do the same thing.  It

seems a waste to have three names to do what amounts to the same thing:

sorting arrays.  The answer is to "overload" a SUBPROGRAM name with

three corresponding pieces of code.  Once subQuickSort is overloaded, it

can do tripple-time thus:
    subQuickSort A%()

    subQuickSort A$()

    subQuickSort UserArray()
Of course, each call invokes DIFFERENT CODE to do the actual sorting,

but this detail is handled by the compiler in a transparent fashion.

The programmer's only responsibility would be to provide the code for

each instance of subQuickSort, in the following manner:
    SUB subQuickSort (Array AS INTEGER)

        |

        |

        code to sort INTEGER arrays goes here

        |

    END SUB
    SUB subQuickSort (Array AS LONG)

        |

        |

        code to sort LONG INTEGER arrays goes here

        |

        |

    END SUB
    SUB subQuickSort (Array AS UserDefinedType)

        |

        |

        code to sort arrays of UserDefinedType goes here

        |

        |

    END SUB
Upon seeing the second instance of subQuickSort in the source listing,

the object oriented BASIC compiler would know that it is dealing with

an overloaded SUBPROGRAM.
Overloading is already done by BASIC compilers, but it is done at a

level not within the control of the programmer.  Consider:
    PRINT a

    PRINT a$
Each case of PRINT prints a different data type.  The PRINT statement,

we could say, then, is overloaded.  Also to consider is the overloading

of operators such as occurs already in BASIC:
    A$ = B$ + C$

    A% = B% + C%
The addition operator is serving two masters here.  In the first case,

it is being used to concactenate strings.  In the second, it is being

used to add two numbers.  The processes are internally dissimilar.

How, then, does the BASIC compiler contend with these cases?  The

addition operator is overloaded at an internal level.  If a programmer

using an object oriented BASIC were to step into the scene, however,

we very well might see this type of overloading of the addition and

assignment operators:
    OVERLOAD "+" FOR ArrayOne(), ArrayTwo()

        TotalElements = UBOUND(ArrayOne) + UBOUND(ArrayTwo)

        DIM ReturnArray(TotalElements)

        FOR i = 1 to UBOUND(ArrayOne)

            ReturnArray(i) = ArrayOne(i)

        NEXT i

        FOR q = i + 1 TO i + UBOUND(ArrayTwo)

            ReturnArray(q) = ArrayTwo(q-i)

        NEXT q

        REDIM ArrayOne(TotalElements)
        ' The following uses an overloaded assingment operator

        ' whose overload definition follows.

        ArrayOne() = ReturnArray()

    END OVERLOAD
    OVERLOAD "=" FOR ArrayOne(), ArrayTwo()

        FOR i = 1 TO UBOUND(ArrayOne)

            ArrayOne(i) = ArrayTwo(i)

        NEXT i

    END OVERLOAD
This bit of sophisticated operator overloading would allow the

programmers to add entire arrays to one another as follows:
    NewList() = ListOne() + ListTwo()
For some readers, all this may be a new concept in programming.  If

it seems hard to understand, please take time to reread this section

before continuing, since the next part of this discussion relies on

the reader's comprehension of all eight terms pertinent to the object

oriented programming paradigm, which are, again:
    1.  Encapsulation,

    2.  Inheritence,

    3.  Polymorphism,

    4.  Overloading,

    5.  Class,

    6.  Method (or Member Function),

    7.  Object (or Class Instance),

    8.  Information or Data Hiding.
[Polymorphism has been purposely avoided for the purposes of this

discussion, due to its rather esoteric nature.]

2.0     BASIC-Specific Considerations of Object Paradigm Implementation
When considering whether BASIC in its present form could

be expanded to include object oriented extensions, we must first look

at what is already possible in standard BASIC.  For example, the

following code resembles inheritence, at least in part:
    TYPE ColorType

        R AS INTEGER

        G AS INTEGER

        B AS INTEGER

    END TYPE
    TYPE CoordinateType

        X AS INTEGER

        Y AS INTEGER

    END TYPE
    TYPE CircleType

        Point AS CoordinateType

        Color AS ColorType

        Radius AS INTEGER

    END TYPE
This is not classical inheritence, but the analogy suffices.  Looking

at the syntactical elements of the above code, we see that a similar

structure could easily be adopted for use with CLASS definitions:
    CLASS CircleClass

        Point AS CoordinateType

        Color AS ColorType

        Radius AS INTEGER

    END CLASS
A question arises, however.  The above definition of the CircleClass

CLASS is not executable code, but merely a definition template.  It

defines CircleClass, but does not assign a "class instance."  That is

to say, there are not yet any objects of CircleClass defined in the

program.  Consider this standard BASIC:
    TYPE AddressType

        Street AS STRING * 10

        City AS STRING * 32

        State AS STRING * 2

        ZIP AS STRING * 12

    END TYPE
    DIM Envelope AS AddressType
The DIM statement is used to create an instance of a variable

called Envelope that is of the user defined type AddressType.  It

makes perfect sense, then, that the DIM statement could be used

in this manner:
    CLASS CircleClass

        Point AS CoordinateType

        Color AS ColorType

        Radius AS INTEGER

    END CLASS
    DIM Orb AS CircleClass
(Remember, having DIM serve this double purpose is known as

overloading the DIM statement.)  This syntax serves our purposes

wonderfully, since it does not involve the introduction of completely

foreign operators and follows the present syntactical structure of

standard BASIC.
Another consideration in the creation of classes is the fact that

classes may contain both variables and methods in their definitions,

as shown in the introduction:
    CLASS FontClass

        FontName AS PUBLIC STRING * 12

        FontPointSize AS PRIVATE INTEGER

        RasterDataPtr AS PRIVATE LONG

        funGetFontPointSize AS PUBLIC FUNCTION

        subSetFontPointSize AS PUBLIC SUB

    END CLASS
This shows a suggested means of expressing both the scope and the

type of each part of the definition.  Note, however, that, although

subSetFontPointSize is defined in this template, there is, as yet,

no code attached to the definition.  It is said, in OOP parlance, that

the "the scope of the member function is unresolved."  The method is

prototyped, but that is all.  In C++, what is known as the "scope

resolution operator" is used to resolve a method, that is, assign

executable code to it.  This is done as follows:
    void FontClass::subSetFontPointSize (int PointSize)

    {

    |

    code to achieve this end goes here

    |

    }
Essentially, this translates into the English statement:
    "Define funGetFontPoint size of the class FontClass as follows...."
In an attempt to avoid convoluted syntactical introductions into the

BASIC language, what follows is a possible solution:
    SUB FontClass.subSetFontPointSize (PointSize AS INTEGER)

        |

        |

        code that assigns the point size goes here

        |

        |

    END SUB
Since the compiler would presumably recognize FontClass as being a

class from the earlier CLASS ... END CLASS block, this should suffice

as a means of resolving the scope of the method subSetFontPointSize,

while avoiding the introduction of :: as a new BASIC operator.
Next comes the issue of overloading both keywords and operators.  A

simple extension of BASIC would allow this to be sufficient in the

case of SUBPROGRAMS and FUNCTIONS:
    SUB subQuickSort (Array AS STRING)

        |

        |

    END SUB
    SUB subQuickSort (Array AS INTEGER)

        |

        |

    END SUB

The second SUB definition would imply overloading. This would be

prototyped at the beginning of the source listing thus:
    DECLARE SUB subQuickSort (Array AS STRING)

    DECLARE SUB subQuickSort (Array AS INTEGER)
Operators, however, are completely different in that BASIC has

no way of referring to them explicitly.  A proposed extension:
    OVERLOAD "=" FOR LeftArgument, RightArgument

        |

        |

        definition code goes here

        |

        |

        result returned in LeftArgument

        |

        |

    END OVERLOAD
Of course, the "=" could be any ASCII character or even multiple

ASCII characters.  This would allow the object oriented BASIC program

to do this, for example:
    OVERLOAD "**" FOR LeftArgument, RightArgument
        ' Some langauges use ** for raising to a power

        LeftArgument = LeftArgument ^ RightArgument
    END OVERLOAD
The following, however, would not be possible, since it would involve

late binding and interpreted evaluation at run-time:
    OVERLOAD Operator$ FOR LeftArgument, RightArgument

        SELECT CASE Operator$

            CASE "**"

                LeftArgument = LeftArgument ^ RightArgument

            |

            |

            etc.

            |

            |

        END SELECT

    END OVERLOAD

2.1     Standardization of Terms in Object Oriented BASIC
Before the discussion continues, perhaps it would be wise to step

aside to establish a set of standard terms.  Since certain

OOP concepts carry many different names (ie. "member function" is

also "method") a standard way of refering to any particular device

should be adopted.  But, really, this could become quite involved;

what is more appropriate, the term "method" or "member function?"

Perhaps, rather than debate too long and hard on the subject,

Microsoft's terminology as used for Visual Basic should be adopted:
    1.  OBJECT rather than "class instance"

    2.  METHOD rather than "member function"

    3.  PROPERTY rather than "member variable"
For terms not used by Visual Basic, I suggest the following use by

object oriented BASIC:
    1.  DATA HIDING rather than "information hiding"

    2.  METHOD DECLARATION rather than "scope resolution"

    3.  METHOD DECLARATOR rather than "scope resolution operator"

    4.  OBJECT BINDING rather than "encapsulation"

    5.  OVERLOADING remains unchanged

    6.  CLASS remains unchanged
I use these substitutes for the other terms because they have a

BASIC sound to them, whereas the other terms, like "scope resolution

operator" may sound odd to BASIC programmers.  DECLARATOR rings of

BASIC's DECLARE statement, thereby reducing the foreigness of the

term METHOD DECLARATOR.  (In case you have forgotten, the :: is

the scope resolution operator in C++, whereas the . is used in this

theoretical object oriented BASIC of ours.)
Using this terminology, we have this model:
      / CLASS VectorClass  ' This is a CLASS DECLARATION

      |     X AS PRIVATE INTEGER   ' This is a PROPERTY of VectorClass

 O B  |     Y AS PRIVATE INTEGER   ' As is this

 B I  |     '    ^^^^^^

 J N  |     ' Use of PRIVATE demonstrates DATA HIDING

 E D  |     ' Whereas use of PUBLIC demonstrates the oposite--\

 C I  |     '                                                 |

 T N  |     '                 /-------------------------------/

   G  |     '               VVVVVV

      |     subSetVector AS PUBLIC SUB ' This is a METHOD

      \ END CLASS
        '  This operator is the METHOD DECLARATOR in this context

        '              |

        '              V

    D / SUB VectorClass.subSetVector ( X AS INTEGER, Y AS INTEGER )

    E |

 M  C |

 E  L |

 T  A |

 H  R |

 O  A |

 D  T |

    I |

    O |

    N \ END SUB

2.2     An Introduction to Advanced Topics in OOP
To this point, most fundemental concepts of the object oriented

paradigm have been examined.  The reader should have a concept of

class, object binding, method declaration, overloading, and

data hiding, and should also understand the essence of how these

object oriented extensions may be added to BASIC.
There are other considerations, however.  When an object is created,

for instance, how is it initialized?  That is to say, how are its

properties set to appropriate starting values?  A typical standard

BASIC program might accomplish this thus:
    CALL subFontInit()
This is fine, but remember that there can be more than one OBJECT of

the same CLASS as in this case:
    DIM Helvetica AS FontClass

    DIM Courier AS FontClass

    DIM TimesRoman AS FontClass
Now, to initialize the data for each of these, we must do something

like this:
    CALL subFontHelveticaInit

    CALL subFontCourierInit

    etc.
In C++, there is away around this that we can adopt for BASIC use.

In every class in C++ there is an implied "constructor."  This is

a new term.  Essentially, the constructor is a method within the

class definition that is executed whenever an object is created.

For an example of this, consider this method declaration:
    SUB FontClass.FontClass

        |

        |

        code to initialize object goes here

        |

        |

    END SUB
(Visual Basic programmers will recognize this as being analogous to

the Load_Form event.)  Note that the method declaration uses FontClass

twice.  This informs the compiler that it is dealing with the explicit

definition of a CONSTRUCTOR.
In the actual binding declaration of the class, this syntax is

suitable:
    CLASS FontType

        |

        etc.

        |

        FontType AS CONSTRUCTOR

        |

        etc.

        |

    END CLASS
The CONSTRUCTOR type then, signifies that this template will be

followed by a method declaration for a constructor.  Now, when the

programmer includes this code:
    DIM Helvetica AS FontType
The compiler will include appropriate initialization routines.
Another aspect of this, the "destructor," is exactly the same, except

that it operates after the object falls from scope.  (Visual Basic

programmers again will note the analagous use of the Form_Unload event.)

Destructors deinitialize data, cleaning up things when the program ends

execution, for instance.  In C++, a special operator is used to indicate

the deconstructor: ~FontClass.  This use of the tilde is foreign to

BASIC, however, so perhaps it would be better to introduce another

keyword rather than a new operator:
    CLASS FontType

        |

        etc.

        |

        FontType AS CONSTRUCTOR

        FontType AS DESTRUCTOR

        |

        etc.

        |

    END CLASS
Now, the method would simply be declared:
    SUB FontType.FontType DESTRUCTOR

        |

        |

        code to deinitialize data structures goes here

        |

        |

    END SUB
This is syntacally familiar to a BASIC programmer in another form:
    SUB subPrintToScreen (InText AS STRING) STATIC

        |

        |

    END SUB
The STATIC keyword modifies the nature of the SUBPROGRAM.  Consquently,

I have suggested the DESTRUCTOR keyword be used in a similar syntactical

fashion.

3.0     Closing Notes
Indeed, BASIC has evolved from the time-sharing days of Dartmouth.

Despite this evolution, however, major software compiler developers

have failed to introduce object oriented extensions into the language.

Perhaps this article has introduced some new concepts to the reader,

perhaps not.  At the very least, it has explored some ways

an object oriented paradigm might be introduced successfully into

BASIC programming with as little pain possible.  Programmers tend to

maintain their old programming habbits despite the innovations that

come into their languages, and consequently, any major changes to

the way BASIC operates may prove to be obstacles rather than useful

tools.  I feel that my suggestions involve minimal relearning of the

syntax of BASIC, since they adopt the flavor of existing structures.

In the end, though, the question is not what is the better method

or terminology to use, really, but rather:
    "Object Oriented BASIC, possibility or pipedream?" 
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

                            BUILDING A LIBRARY

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Writer: Chris Charabaruk
Instead of having some dumb ole introduction, I am going to cut to the chase

here regarding making your own library. I'm sure you've thought of making

something to compete with Future.Library or DirectQB, but for this article,

I won't be dealing with making a library like those. Instead, I will describe

to you how to create a library with your own routines or with other people's

OBJ files.
A library is really nothing except a bunch of OBJ files each with one or more

routines (read SUBs or FUNCTIONs) inside, none of which are called main

(main is only found in executable files). Let's not discuss libraries for a

minute though, I want to talk about these routines. In languages like C or

C++, everything is in a routine, even the actual program. You see, when the

operating system runs an executable file, it actually calls the main()

routine inside the program. main() is like a FUNCTION, because it takes in

an array of characters (a string) and returns an integer value. In C/C++ you

write the main() routine like this:
int main()

{

// code goes here

return 0

}
Each QuickBasic program that's compiled has this main() routine as well,

except that by just using QB, you can't return an "errorcode" (the value that

main() returns). There is a way, however, but I won't be telling you about

it here. A SUB in QuickBasic is similar to a FUNCTION when written in C/C++,

it looks like this:
void mysub()

{

// code goes here

}
The "void" means that the routine does not return a value, unlike the main()

routine above which returns an integer with value 0. Since mysub() is void,

you can forget about putting in "return", or you can add "return null" which

says to the compiler, return nothing. Now that we have covered routines,

now we can go on to OBJ files.
An OBJ (object) file is nothing more than one or more routines ready to be

put in a library or linked to make an executable file. When you use

QuickBasic's compiler at the command line, all that it does is generate a

bunch of OBJ files. Then, you have to use the LINK program to turn them into

an executable, or LIB to make them into a library. If you use the options in

QB or QBX's run menu, it does the entire process of compiling and

linking/libbing for you, but you have less control over it all. I generally

use the command prompt or a makefile to do the job for me.
So you have the routines, you've used the compiler to make the OBJ files (or

you've found some OBJ files that you know have some useful stuff in them),

now how to make it into a library you can use in QuickBasic? Well, actually,

to make a library for QB, you have to use LINK as well as LIB. You need LINK

to make the QLB file for running the program that needs the routines inside

the IDE and the LIB file for compiling. So let's look at how to make this

library.
LIB, according to it's online documentation that came with MASM 6.11, is to

create and to maintain libraries of compiled or assembled object modules.

LINK, on the other hand, is to create an executable program out of these OBJ

files. So how does that help us make a QLB file? Well, the version of LINK

that comes with QB4.5 and all of Microsoft's PDS packages have a /Q switch

which tells LINK to make a QLB file instead of an EXE. So say that your

routines are in the object files mysubs.obj and myfuncs.obj, to make a

QuickLibrary named mylib.qlb, use this line at the command prompt:
LINK /Q mysubs.obj myfuncs.obj, mylib.qlb,,qbqlb.lib;
Or if you use QBX/PDS use this instead:
LINK /Q mysubs.obj myfuncs.obj, mylib.qlb,,qbxqlb.lib;
That makes the QLB file. To make the normal LIB file, you use LIB like this:
LIB mylib.lib + mysubs.obj + myfuncs.obj
So now you have your library. But later on, you have some more routines

(new.obj) you want to add. So rename your mylib.lib and mylib.qlb files to

myoldlib.lib and myoldlib.qlb, and do this to rebuild the QLB:
LINK /Q new.obj myoldlib.lib, mylib.qlb,,qbqlb.lib;
Or for QBX:
LINK /Q new.obj myoldlib.lib, mylib.qlb,,qbxqlb.lib;
To rebuild the LIB file:
LIB mylib.lib + new.obj + myoldlib.lib
So there you go. There's one more topic that I want to mention though,

granularity. When you use a library, all the routines that share an OBJ with

the ones you were using are included in the program. It's better to have each

routine in it's own file because this way, only what is used from the library

is incorporated into your program. On the other hand, if a routine in your

library needs to call another included routine, then it's best to have them

share a BAS file, and therefore a OBJ file.
Well, that's the basics of making your own library. If I was too confusing,

then just email me at evilbeaver.picksoft@zext.net and I will help you

further if I can. 
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

                    INTRODUCTION TO QBASIC SERIES #3

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Writer: Matthew River Knight
Welcome to the third part in the Introduction to Qbasic Series! We went

over quite a lot of information last time, having covered some more of the

capabilites of Qbasic with regard to the handling of text, demonstrated how

to allow the user input from the keyboard, did some LOOPing, and we even took

a brief look at how to display graphics in Qbasic. This time I'd like to 

cover some more of these simple things before we go onto more difficult areas

of programming, hopefully picking up some information that we left out along

the way.
First of all, let's take a look at what else we can do with Qbasic as far as

text handling is concerned. For starters, it would be nice if we could place

text at a specific location on the screen wouldn't it? Lucky for us, Microsoft

wrote made a nice little routine to do this for us. This is the LOCATE 

statement. The LOCATE statement tells the computer at which location on the

screen the next PRINTed text must be placed. You'll recall that last issue,

in order to explain how PSET works, I described the screen as a grid. When

using LOCATE you also have to think of the screen as a grid, but it works

a little differently. The 'grid' that we're talking about when using LOCATE

is not made up of pixel spaces, it is made up of much larger blocks that are

basically the same size as your average ASCII character. And what is an 

ASCII character you ask? Well, all the letters and numbers you see on the

screen in DOS are ASCII characters. Apart from the number and letter

characters, there are also some other ASCII's which look quite strange. You

have seen some of them before. Some of them are used by the Qbasic editor

to draw the menu's and the scrollbar, etc. ASCII stands for American Standard

Code for Information Interchange. 
Another way of thinking about how LOCATE works is like this: suppose you

wanted to put some text, for example "Qbasic rulz!", 5 ASCII spaces across

the screen, and 10 ASCII spaces down. Then all you'd have to do is this:
LOCATE 10, 5

PRINT "Qbasic rulz!"
Try experimenting with different numbers and see what results you get. Using

LOCATE will make your life much easier when using text! There are some other

similar text handling routines, but there is no need to use them since LOCATE

is generally capable of doing exactly the same as them, but is easier to use

and more versatile.
Okay, now onto something more fun ^_^ Last time when we looked at using

graphics in Qbasic we really didn't do very much. All we used was PSET and

LINE - not too interesting. So we'll cover some better stuff this time round.
It is sometimes necessary that you know the color code of a certain pixel on

the screen. You can actually do some pretty cool graphics effects just by

knowing this simple information. In Qbasic, we use the POINT statement to

obtain the color code of a certain pixel on the screen. The POINT statement

is very versatile in the way that it may be used, and this makes it very

easy to understand.
For example, if you wish to get the color of a pixel at the coordinates (2,5)

on the screen 'grid' into the Col variable then all you do is this:
PSET (2, 5), 2  'Place a green pixel at coodinates (2,5)

Col = POINT(2, 5)  'Get the color code of the pixel at (2,5)
You can also use POINT like this:
IF POINT(2, 5) = 2 THEN PRINT "That pixel is green"
Try playing around with this, and maybe you'll figure out how to do something

cool using a combination of POINT and one of the other Qbasic drawing routines.

I once wrote a little program using PSET and POINT that allowed you to print

text on the screen, and it melted what looked like lava around it. There is

no reason why you couldn't write a program to do exactly that!
Okay, now on to something a bit more cool. You have probably found that using

LINE to draw graphics is rather difficult and time consuming. There is

another Qbasic command for drawing that is much easier to use. It's called

DRAW! It works quite unlike any other Qbasic routines we have covered so

far, as you'll soon see.
The DRAW statement has its own commands for doing things. For example, it

has the U command for drawing lines up, and the D command for drawing lines

down. Let's demonstrate this by means of an example:
SCREEN 13

PSET (10, 10), 2  'Start drawing at (10,10) in green

DRAW "U100"  'Draw a line up, 100 pixels in length
PSET (100, 100), 14  'Start drawing at (100,100) in yellow

DRAW "D20"  'Draw a line down, 20 pixels in length
There are lots of commands used with DRAW, but you'll probably never use half

of them. We'll cover the most commonly used ones. If you want to know the

others then you'll have to take a look at the Qbasic help file.
You have probably already guessed that in order to draw right, you use the

DRAW command R, and to draw left you use L. This should have been obvious.

But what if you want to draw diagonally? Well, to draw diagonally up and

right you use the DRAW command En, where n is a number specifying the pixel

length of the line to be drawn. To draw diagonally down and right you use the

commnd, F. To draw diagonally down and left you use G, and lastly, to

draw diagonally up and left you use H. Simple no? Okay, here's an example:
SCREEN 13

PSET (160, 100), 2  'Start drawing at (160,100) in green

DRAW "H20 E20 F20 G20"
Note that I have put a space between each of the DRAW commands in order to

make it easier for you to read. You don't have to do it this way though. You

could just as easily have left them out, and it would do exactly the same

thing. Like this:
SCREEN 13

PSET (160, 100), 2  'Start drawing at (160,100) in green

DRAW "H20E20F20G20"
It really doesn't make a difference. 
Another usefull DRAW command is C which sets the DRAWing color. All you do

is say Cn where n is the color code of the color in which you'd like to 

DRAW, and voila - you're DRAWing in that color. Could it really be any 

easier?! Let's demonstrate this by means of an example:
SCREEN 13

PSET (160, 100), 2  'Start drawing at (160,100) in green

DRAW "C2 H20 C3 E20 C4 F20 C5 G20"
Once again you can see that I've put spaces between each of the DRAW commands

in order to make this easier to read and understand. If I were writing a 

program in which readability was not a necessity, I'd have left the spaces

out since they're a waste of space.
There are many other DRAW commands that can be used, but I'm not going to 

cover it all here, when there is a perfectly good description of all of them

sitting right there in the Qbasic help files. One thing that I should 

mention before we go onto something else is that you are able to use DRAW 

with strings instead of specifying it right after the command. This allows

you to save a lot of space. To clarify this further, here's an example:
Diamond$ = "C2 H20 C3 E20 C4 F20 C5 G20"

SCREEN 13

PSET (160, 100), 2  'Start drawing at (160,100) in green

DRAW Diamond$
In the above example you can clearly see that we have used DRAW with a string

variable, instead of placing all the commands right after the DRAW statement.

You will find this ability very usefull when you find the need to DRAW an

object more than once. Without this ability you'd have to specify all those

commands to draw the object again, and again, and again, which is really a

waste of space.
Right. Now we've covered PSET, POINT, LINE and DRAW. With that you can, with

some ingenuity, draw some fairly good graphics. But what if you want to draw

a circle? Can you imagine writing the DRAW code for all of that! Yeah, it 

would be a total nightmare! Fortunately there is a Qbasic statement called

CIRCLE which allows you to draw circles. It's actually a bit more versatile

than that in the light that it can not only draw circles, but also ellipses,

and fractions of circles/elipses. It's a really great little routine. So

let's learn how to use it!
We'll start off using CIRCLE just to do simple stuff, and then we'll work

our way up, step-by-step, finally getting onto some more difficult stuff.
Okay. In order to draw a yellow (color code 14) circle with a radius of 15 at

the coordinates (160,100) on the screen 'grid' we'd type the following code:
SCREEN 13

CIRCLE (160, 100), 15, 14
Now that wasn't so hard, was it? Right, now that we've mastered the drawing

of circles, I think it's time that we move onto ellipses. You may not have 

heard of an ellipse before, so this is what it is: an ellipse is, in the

most simple terms I can think of, basically like a squashed circle! You can

probably imagine what I mean. It can be squashed from the top, or from the

side. It doesn't really matter. Any squashed circle is an ellipse!
Let's, for example, say you wanted to have a circle that looked squashed 

from the top. First thing you have to think about is how squahed you want it

to be. If we wanted to squash the circle, from the top, by 50% then we'd do

this:
SCREEN 13

CIRCLE (160, 100), 15, 14, , , 50 / 100
If we wanted it squashed by 70%, from the top, then we'd do this:
SCREEN 13

CIRCLE (160, 100), 15, 14, , , 30 / 100
Simple no? Unfortunately, although we are able to describe the squashing 

effect in degrees here, the CIRCLE routine doesn't actually think of it that

way, and that makes life quite difficult when we want to squash a circle

from the sides - the degrees thing doesn't work anymore. It actually works

like this: the division (above it is 29/100) which is actually called the

aspect describes the ratio of the x radius to the y radius (x;y). The 

defualt aspect ratio depends on the screen mode, but gives a visual circle

in any graphics mode, assuming a standard monitor screen aspect ratio of 4:3.
Did that make you a little dizzy? Yep? Okay, well, then let's go about it

this way...practise! Play around with this until you understand! That's the

best way to understand programming. Just to get you started, here's an

example program showing you how to squash a circle from the side:
SCREEN 13

CIRCLE (160, 100), 15, 14, , , 170 / 100
Play around with this and it'll soon make sense.
Okay, as I mentioned earlier, it is possible to draw fractions of the circle,

but that is slightly mathematical so I'll leave that for another time. I

think I've confused you enough for one day!
There are still other graphics routines to cover, but we'll have to leave 

that for another issue. We have said more than enough about graphics this

month!
Okay, we'll cover one more aspect of programming before I leave you to play

around with what you've learned this issue. Sound in Qbasic! Before we 

even start this I need to explain one simple thing - Qbasic is, ordinarily,

only able to produce sound through the internal PC speaker. You probably

didn't even know that you have a speaker inside your computer, but you do.

In the old days of computing there was no such thing as sound cards, and

sound amplifiers for the computer. Such things were unheard of. In those

days everyone used to have to play sound through the little speaker inside

the computer. Unfortunately the internal speaker is really junky. Any sound

that comes from it sounds terrible. But, as a newbie, it's the only sound 

that'll be available to you for a while. There are ways to use the sound 

card in Qbasic, but it's really difficult, so we are not going to cover that

at this stage.
Okay, I have rambled on long enough! We have quite a few Qbasic statements

at hand which generate sound through the PC speaker. We'll start off with

some simple stuff. It's fairly clear that the simplest form of sound we

could possibly get the computer to do is just a beep. What could be easier 

than that? Well, there is a Qbasic statement called BEEP that does just that!

BEEP generates a beep-like noise from the internal speaker at 800hz (800 

cycles per second) for one-quarter of a second. It's really easy to use 

BEEP. Let's test it:
BEEP
Yep! That's it! That's all you have to type to use BEEP. Could anything be

any easier than that?! Well congratulations, you've just mastered yet another

Qbasic statement, and it's only taken you two seconds! ^_^
Okay, soon you're likely to get bored with BEEP. With BEEP you are not able

to specify the pitch of the BEEP and the duration for which it plays. And

that is no good. No good at all. Okay, well this isn't much of a problem.

There is a Qbasic statement called SOUND which allows you to do exactly 

what BEEP won't allow you to do! The syntax of SOUND is:
SOUND frequency, duration
frequency is the pitch of the sound. For those of you who don't know what this

means (get a dictionary!) here's some examples - an example of a low pitch

would be thunder. It sounds deep and has a low pitch. An example of a high

pitch would be the squeek of a mouse. It has a high pitch. The higher the

number is in place of frequency, the higher the pitch of the sound. The 

frequency may not be lower than 37, and not higher than 32767.
duration specifies the amount of time the computer has to spend making the

sound. It is measured in clock ticks. Clock ticks occur 18.2 times per 

second. The duration may not be less than 0, and not higher than 65535.
Ah, okay, now is a good time for an example, no?
SOUND 300, 70
If you really want to give yourself a headache (why would you want to do 

that?!) then run the following program:
SOUND 5000, 65535
I would not advise running that program. You'll get a terrible headache. You

could easily write a program that would trick somebody into thinking there's

a mosquito in the room ;)
Now the problem with this stuff is that it's really hard to write music 

with it. It's even harder to try and write sound effects. With music we

are accustomed to sounds being described as A,B,C,D,E,F and G. Well 

here's a list of the equivelent frequency's for them! ^_^
I took this list from a book I have on Qbasic. For some reason there are

a number of different A's, B's, C's...etc. I know nothing about music so

I have no idea why this is the case. Those of you who know about music will

be able to make more sense of this than I can ;)
Note   Frequency   Note   Frequency
C      130.810     C*     523.250

D      146.830     D      587.330

E      164.810     E      659.260

F      174.610     F      698.460

G      196.000     G      783.990

A      220.000     A      880.000

B      246.940     B      987.770

C      261.630     C     1046.500 

D      293.660     D     1174.700

E      329.630     E     1318.500

F      349.230     F     1396.900

G      392.000     G     1568.000

A      440.000     A     1760.000

B      493.880     B     1975.500
*Middle C.
By doubling or halving the frequency, the coinciding note values can be 

estimated for the preceding and following octaves.
To produce periods of silence, use the following statement:
SOUND 32767, duration
To calculate the duration of one beat, divide the beats per minute into the

number of clock ticks in a minute (1092).
The following table illustrates tempos requested by clock ticks:
Tempo       Notation       Beats/Minute       Ticks/Beat
very slow   Larghissimo

            Largo          40-46              27.3-18.2

            Larghetto      60-66              18.2-16.55

            Grave

            Lento

            Adagio         66-76              16.55-14.37

slow        Adagietto

            Andante        76-108             14.37-10.11

medium      Andantino

            Moderato       108-120            10.11-9.1

fast        Allegretto

            Allegro        120-168            9.1-6.5

            Vivace

            Veloce

            Presto

very fast   Prestissimo
Like I said, I know nothing about music, and I thus have no idea what the

above table is talking about. The only thing that I know about music is

that it comes out of the radio! ;) Those of you who know about music will

probably find the above information very usefull, but as for the rest of you

who know no more about that stuff than me, don't worry about it. It's still

possible to do cool stuff with SOUND without any knowledge of music.
There's another way to use music with the internal speaker in Qbasic, but

we'll cover that (and other things) next issue. Until next month, just play

around with what you have learned, and see if you can come up with something

cool. If you make a little program, and you are proud of it and would like

others to see it, then email it to me at horizonsqb@hotmail.com and I'll

include with the next issue of the QBCM! Have fun with Qbasic!!! ^_^
Cya next month!  
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

                       MANIPULATING SOUND IN QBASIC

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
(A while ago I found a bunch of ZIPs which contained posts from old Qbasic

BBS's. Most of the posts were from 1991-93. A lot of the information in the

ZIP's was either very primitive or was just code with no explanation of

how it works. I did however find this one good tutorial which explains some

very cool stuff about the use of sound in Qbasic. This document has been

left in its original state. -ed)
 From:  EDWARD SCHLUNDER          Sent: 07-24-93 05:18

   To:  MATTHEW MCLIN             Rcvd: -NO-

   Re:  FORMAT OF MOD, SAM (1/9)
<-=-=-=-=- Matthew Mclin to All -=-=-=-=>

 MM> Does anybody know the format of MOD/SAM/WAV/VOC file? Info on any

 MM> of those formats (how to read/write/play them using a PC Speaker

or

 MM> LPT 1 with a mono DAC) would be greatly appreciated.
      You know, you are quite lucky that I just decided to pickup the

   Pascal echo even though I'm not a Pascal programmer. I have ALL of

   these file formats! Lucky you! I have had to search high and low all

   over the place for this junk and you're getting it all in one shot.
      Not only do I have those file formats, but I also understand how

   to play them back on the PC's Internal Speaker, LPT DACs, and Sound

   Blaster. I'll be posting that too.
      I have been interested in this field for quite a while, that's how

   I gather up all this information. If I had enough ambition, time, and

   patience, I'd probably write a book on it all because there is not

   ONE SINGLE book that explains how to play digital sound directly (ie,

   without specail drivers), with such drivers, what the file formats

   are, and includes code to do all that stuff.
      Gee, I bet that would make a lot of money, perhaps I should do

   that after all.... Those guys on the 80XXX Assembler echo would

   probably be able to do a better job as they are more knowledgable on

   this, but most of them are into writing demos and creating

   faster/better MOD players..
      Ok, since this will take up a lot of room, I'll be splitting it up

   into seperate messages. The simpilest stuff goes in this message.
 MM> I would also like info on raw sound data and how to edit/play it.
      Newbe to Digital Sound, eh? Well, you've come to the right place

   for information, or rather, the right person has come to you. Ok, the

   basics. A digital sound file is basically just a bunch of volume

   settings. On the PC, a volume setting of 128 is normally silence.

   Values farther away from 128 in either direction are louder depending

   on its distance from 128. 0 and 255 are the loudest volumes. One

   thing I should make clear, 128 is not nessicarily silence. When

   making a recording, there is always background noise. So, what may

   sound like silence to you, is actually 126-130 or so.
      Now, you have probably seen those neat little graphs that some

   programs make when displaying a digital sound file. VEdit (which

   comes with the Sound Blaster) shows the waveform in the modify part

   of it. If you wanted to display a graph yourself, you could just load

   in a byte from the file, then, use that byte for the Y location. The

   X location is where in the file you are at (which byte). You just

   keep loading in bytes until the end of the screen. I could go on and

   on, but this is just a message, not a book! Hmm, you said you wanted

   to play a digital sound file on the PC's Internal Speaker and on a

   printer port DAC. Well, here comes that part. I'll explain usage of

   printer port DACs first because they are easier to understand. To

   play a VOC, WAV, SND, etc file on the DAC, you just read in one byte

   from the file, output it to the printer port, and do it again but on

   the next byte. To get the I/O address of the printer port, read the

   word at memory location 40h:8h for LPT1, 40h:0Ah for LPT2, 40h:0Ch

   for LPT3, and if on a non-ps/2, 40h:0Eh for LPT4.
      The internal speaker is a bit more tricky, you have to do certain

   things to set it up correctly before outputting sound. Before you do

   ANY sound output, you must do the following (sorry, I'm not a Pascal

   programmer, so this is in Assembler):
   Out   43h, 0B6h                     ;Please make note: This code was

   Out   42h, 0FFh                     ;written by a friend of mine in

   Out   42h, 0                        ;australia named Phil Inch. He

   Out   43h, 90h                      ;posted code in the 80x86 Assembler

   In    ax, 61h                       ;echo (GTPN, not Fido) for the

   Or    ax, 3                         ;public domain. Thanks Phil!!

   Out   61h, ax
      Ok, the above sets the timer chip up correctly. From there it is

   pretty simple. Get a byte from the sound file. Divide the byte by a

   'shift' number (I'll explain about this later). Then, output this new

   byte to port 42h. Repeat this for the whole file.
      Ok, now, about that shift value. The PC's Internal Speaker wasn't

   designed for playing digital sound on it, it's just that brainy guys

   like Phil have figured out how to do with software what should have

   been done with hardware.. Anyway, the PC's Internal Speaker isn't

   very loud, so the range of volumes is much less than on a Sound

   Blaster or printer port DAC. This shift value varies from computer to

   computer, it depends on the size of your speaker and other stuff.

   Genernally, a shift value of 4 works on all computers. On my

   computer, I can get anyway with 3 on most files. The smaller the

   shift value, the louder the file will be played, but too small a

   shift value will cause distortion. Experiment! After you are finished

   playing the sound file, you must put the timer chip back the way it

   was supposed to be, or otherwise the next program that tries to make

   a noise on the internal speaker will make the noise but will not

   stop! Here is the code for that (again, sorry about the Assembler,

   it's just that I'm not a Pascal programmer):
   Out   43h, 0B6h

   In    ax, 61h

   And   ax, 0FCh

   Out   61h, ax
      There, that should do it. I hope I haven't totally confused you.

   Please write back if you have ANY questions what-so-ever. Gee, I'm

   already on line 107, time to go to a new message!

<-=-=-=-=- Matthew Mclin to All -=-=-=-=>

 MM> Note that these .MOD

 MM> and .SAM files are in the Amiga Module format (just incase there are

 MM> any others). Oh, there's also the .SND files. Or even .MID/.MDI files

 MM> if you can play them thru a DAC on an LPT port or the PC Speaker. Note

 MM> that I don't have a Sound Blaster (or any other sound card). Thanks.
SAM Files:
      As far as I know, these do not contain any header or specific

   structure. They are just raw sound files. The only trick you have to

   remember about these files are that they are signed, which means that

   when the 7th bit is set, the number is negative. When the 7th bit is

   clear, the number is positive. This is completely different from

   digital sound files that originated on the PC. Remember, MOD and SAM

   files originated from the Amiga, so they have this weird encoding.
     To convert a signed file to an unsigned file, just read in one byte

   from the original file. Add 128 to that byte. Output the answer to a

   new file. In the Amiga world, a byte of 0 is equalivilent to silence.

   A byte of -128 (and +128) is as loud as it gets on the Amiga.  On the

   PC, however, 0 (and 255) is as loud as it gets. A byte of 128 is

   equalivilent to silence on the PC. So, when we add 128 to a -128, we

   get a zereo, which is the same volume for a 128 on the Amiga.
      The following text was written by Edward Schlunder and was based

   on information provided by Tony Cook on the GT Power Network's 80x86

   Assmebler echo.
                               WAV File Format

                       By: Edward Schlunder. 5-17-93
 BYTE(S)        NORMAL CONTENTS               PURPOSE/DESCRIPTION
-----------------------------------------------------------------------

 00 - 03        "RIFF"                        Just an identification block.

                                              The quotes are not included.
 04 - 07        ???                           This is a long integer. It

                                              tells the number of bytes long

                                              the file is, includes header

                                              size.
 08 - 11        "WAVE"                        Just an other I.D. thing.

 12 - 15        "fmt "                        Just an other I.D. thing.
 16 - 19        16, 0, 0, 0                   Size of header to this point.

 20 - 21        1, 0                          Format tag.
 22 - 23        1, 0                          Channels
 24 - 27        ???                           Sample rate, or (in other

                                              words), samples per second.
 28 - 31        ???                           Average bytes per second.
 32 - 33        1, 0                          Block align.
 34 - 35        8, 0                          Bits per sample. Ex: Sound

                                              Blaster can only do 8, Sound

                                              Blaster 16 can make 16.

                                              Normally, the only valid values

                                              are 8, 12, and 16.
 36 - 39        "data"                        Marker that comes just before

                                              the actual sample data.
 40 - 43        ???                           The number of bytes in the

                                              sample.
VOC File Format:
      This file format was written by Phil Inch on the 80x86 Assembler

   echo on the GTPN. Thanks Phil!!
BYTE(S)        NORMAL CONTENTS               PURPOSE/DESCRIPTION

-----------------------------------------------------------------------
00 - 19        "Creative Voice File", 26     Just an identification block.

                                             The quotes are not included,

                                             and the 26 is byte 26 (1Ah) which

                                             is an end-of-file marker. There-

                                             fore, if you TYPE a VOC file, you

                                             will just see Creative Voice File.
20 - 21        26, 00                        This is a low byte, high

                                             byte sequence which gives

                                             the offset of the first

                                             block of sound data in the

                                             file.  Currently this is 26

                                             ( 00 x 256 + 26 ) which is

                                             the length of the header,

                                             but it's probably good

                                             programming practice to

                                             read and use this value

                                             anyway in case the format

                                             changes later.
22 - 23        10,1                          These bytes give the

                                             version number of the VOC

                                             file, subnumber first, then

                                             main number. The default,

                                             as you can see, is 1.10.
24 - 25        41,17                         These bytes are "check

                                             digits". These allow you to

                                             be absolutely SURE that you

                                             are working with a VOC

                                             file.  To use them, convert

                                             the version number (above)

                                             and this number to

                                             integers. Do this with the

                                             formula below, where for

                                             convention the above bytes

                                             have been listed as byte1,

                                             byte2.
                                             (byte2*256)+byte1

                                             Therefore, for the default

                                             values we get the following

                                             integers:
                                             (1 x 256)+10 =  266 (17

                                             x 256)+41    = 4393
                                             When you add the two

                                             results, you get 4659.  If

                                             you do these calcs and get

                                             4659, then you can be

                                             almost certain you're

                                             working with a VOC file.
OK, that takes care of the header information.  I hope you realise that

I'll never get a registration for VOCHDR now!  Oh well <sigh> perhaps

people will buy my games!
   Having gotten to byte 26, we now start encountering data blocks.

There are eight types in all, conveniently numbered 0 - 7.  For each

block, the first byte will always tell you the type.
For notational convenience, bx means byte x, eg b5 means byte 5.
BLOCK 0 - THE "END BLOCK"
   Structure:     Byte 1: '0' to denote "end block" type
   This block is located at the END of a VOC file.  When a VOC player

   encounters a block 0, it should stop playing the VOC file.

BLOCK 1 - THE "DATA BLOCK"
   Structure:     Byte 1: '1' to denote "data block" type
                       2: \

                       3: | These bytes give the length:

                       4: / b2 + (b3*256) + (b4*65536)
                       5: Sampling rate: Calculated as 1000000 / (256-b5)
                       6: Pack type byte:

                              0 = data is not packed

                              1 = data is packed to four bits

                              2 = data is packed to 2 bits

                              3 = data is packed to 1 bit
                       7: Actual sample data starts here

BLOCK 2 - THE "MORE DATA BLOCK"
   Structure:     Byte 1: '2' to denote "more data block" type
                       2: \

                       3: | These bytes give the length:

                       4: / b2 + (b3*256) + (b4*65536)
                       5: Actual sample data starts here
   The point of this is simple:  If you have a sample that you want to

   chop up into smaller portions (the maximum block length in a VOC file

   is 16,842,751 bytes but who's counting?), then define a "more data"

   block. This "carries over" the previously found sampling rate and

   pack type byte, so a "data block" should have been encountered

   earlier somewhere along the line.

BLOCK 3 - THE "SILENCE" BLOCK
   Structure:     Byte 1: '3' to denote "silence block" type
                       2: \

                       3: | These bytes give the length:

                       4: / b2 + (b3*256) + (b4*65536)
                          (Note that this value is usually 3 for a

                          silence block.)
                       5: Duration ( b5+(b6*255) ).  This gives the equivalent

                       6: number of bytes to "play" during the silence.

                       7: Sampling rate: Calculated as 1000000 / (256-b5)
   A silence block is used for long periods of silence.  When long

   silences are required, it's more efficient in size terms to insert

   one of these blocks, as seven bytes can then represent up to 65,536.
BLOCK 4 - THE "MARKER BLOCK"
   Structure:     Byte 1: '4' to denote "marker block" type
                       2: \

                       3: | The length of the block, as usual

                       4: /
                       5: Marker value, as low-high (ie b5 + (b6*255) )

                       6:
   The marker block is read by CT-VOICE.DRV.  When a marker block is

   encountered, the value in the marker value bytes (5 and 6) is copied

   into the status word specified when CT-VOICE was initialized.
   This allows your program to judge where in the sample you currently

   are, thus allowing for progress counters and the like.  It's also

   useful if you're trying to synchronize other processes to the playing

   of the sound.
   For example, by using appropriate marker blocks, you could send

   signals to your software to move the lips of a person on-screen in

   time with the speech in the VOC.  However, this does take some doing

   and a VERY good VOC editor!

BLOCK 5 - THE "MESSAGE BLOCK"
   Structure:     Byte 1: '5' to denote "message block" type
                       2: \

                       3: | The length of the block, as usual

                       4: /
                   5 - ?: Message, as ASCII text.
                       ?: 0, to denote end of text
   The message block simply allows you to embed text into a VOC file.

   Presumably you could use this to detect when other people have

   pinched your VOC files for their own applications.

BLOCK 6 - THE "REPEAT BLOCK"
   Structure:     Byte 1: '6' to denote "repeat block" type
                       2: \

                       3: | The length of the block, as usual

                       4: /
                       5: Number of times that data should be repeated

                       6: Total = 1 + b5 + (b6*255)
   Every "playable" data block between a block 6 and a block 7 will be

   repeated the number of times specified in b5 and b6.  Note that you

   add one to this value - the data blocks are ALWAYS played at least

   once.  However, if b5 and b6 are zero, then you really don't need a

   repeat block, do you!
   I'm told that you cannot "nest" repeat blocks, but I've never tried

   it. This limitation would only apply to CT-VOICE.DRV I would have

   thought, but it depends how good other VOC players are.

BLOCK 7 - THE "END REPEAT BLOCK"
   Structure:     Byte 1: '7' to denote "end repeat block" type
                       2: \

                       3: | The length of the block, as usual

                       4: /
   This, as explained, marks the end of the block of blocks (!) that you

   wish to repeat.  Note that the "length" is always zero, so I don't

   know why the length bytes are required at all.

   There, finally... Ahh. Well, next up is the MOD and SND file

formats...
This was picked up off the 80XXX Assembler echo on FidoNet. There are

many other file formats for MODs, but I have found this one to be most

complete
Protracker 2.3A Song/Module Format:

-----------------------------------
Offset  Bytes  Description

------  -----  -----------

   0     20    Songname. Remember to put trailing null bytes at the end...

               When written by ProTracker this will be only uppercase;

               there are only historical reasons for this. (And the

               historical reason is that Karsten Obarski, who made the

               first SoundTracker, was stupid.)
Information for sample 1-31:
Offset  Bytes  Description

------  -----  -----------

  20     22    Samplename for sample 1. Pad with null bytes. Will only

               be uppercase.  The samplenames are often used for storing

               messages from the author; in particular, samplenames

               starting with a '#' sign will generally be a message.
               This convention is a result of a player called

               IntuiTracker displaying all samples starting with # as a

               message to the person playing the module.
  42      2    A  WORD with samplelength for sample 1.  Stored as number of

               words.  Multiply by two to get real sample length in

               bytes. This is a big-endian number; for all PC

               programmers out there, this means that to get your

               8-bit-orginated format, you have to swap the two bytes.
  44      1    Lower four bits are the finetune value, stored as a

               signed four bit number. The upper four bits are not used,

               and should be set to zero. They should also be masked out

               reading; you can never be sure what some stupid program

               could have stored here...
   45      1   Volume for sample 1. Range is $00-$40, or 0-64 decimal.
   46      2   Repeat point for sample 1. Stored as number of words

               offset from start of sample. Multiply by two to get

               offset in bytes.
  48      2    Repeat Length for sample 1. Stored as number of words in

               loop. Multiply by two to get replen in bytes.
Information for the next 30 samples starts here. It's just like the info

for sample 1.
Offset  Bytes  Description

------  -----  -----------

  50     30    Sample 2...

  80     30    Sample 3...

   .

   .

   .

 890     30    Sample 30...

 920     30    Sample 31...
Offset  Bytes  Description

------  -----  -----------

.

 950      1    Songlength. Range is 1-128.

 951      1    This byte is set to 127, so that old trackers will search

               through all patterns when loading. Noisetracker uses this

               byte for restart, ProTracker doesn't.
 952    128    Song positions 0-127.  Each hold a number from 0-63 (or

               0-127) that tells the tracker what pattern to play at

               that position.
1080      4    The four letters "M.K." - This is something Mahoney &

               Kaktus inserted when they increased the number of samples

               from 15 to 31. If it's not there, the module/song uses 15

               samples or the text has been removed to make the module

               harder to rip. Startrekker puts "FLT4" or "FLT8" there

               instead. If there are more than 64 patterns, PT2.3 will

               insert
               M!K! here. (Hey - Noxious - why didn't you document the

                           part here relating to YOUR OWN PROGRAM? -Vishnu)
Offset  Bytes  Description

------  -----  -----------

1084    1024   Data for pattern 00.

   .

   .

   .

xxxx  Number of patterns stored is equal to the highest patternnumber

      in the song position table (at offset 952-1079).
  Each note is stored as 4 bytes, and all four notes at each position in

the pattern are stored after each other.
00 -  chan1  chan2  chan3  chan4

01 -  chan1  chan2  chan3  chan4

02 -  chan1  chan2  chan3  chan4

etc.
Info for each note:
 _____byte 1_____   byte2_    _____byte 3_____   byte4_

/                \ /      \  /                \ /      \

0000          0000-00000000  0000          0000-00000000
Upper four    12 bits for    Lower four    Effect command.

bits of sam-  note period.   bits of sam-

ple number.                  ple number.

      One thing you should keep in mind about MOD files is that they

   originated from the Amiga, so the samples are signed, see the

   discussion about SAM files for more information.
   Note:

      Sounder and Sound Tool both use the same file extension, but have

   different file formats. To tell the difference, Read the first 6

   bytes of the file. If it matches the magic number for Sound Tool .SND

   files, it is a Sound Tool file. Else, it's a Sounder file or a raw

   file.

Sounder File Format:
 BYTE(S)        NORMAL CONTENTS               PURPOSE/DESCRIPTION
-----------------------------------------------------------------------
 00 - 01        0, 0                          Bits per sample. Ex: Sound

                                              Blaster can only do 8,

                                              Sound Blaster 16 can make

                                              16. Normally, the only

                                              valid value is 0, which is

                                              the code for an 8 bit

                                              sample. Future versions of

                                              Sounder and DSOUND.DLL may

                                              allow 16 bit samples and

                                              such.
 02 - 03        ???                           Sampling rate. Currently,

                                              only 22 KHz, 11 KHz, 7.33

                                              KHz, and 5.5 KHz are

                                              valid. If given a value

                                              like 9 KHz, it will be

                                              played at the next closest

                                              rate (in this case, 11

                                              KHz). The sampling rate is

                                              calculated as follows:
                                              SampRate = Byte1 + (256 * Byte2)

 04 - 05        ???                           Volume to play the sample

                                              back at. Note: On the PC's

                                              Internal Speaker, there is

                                              a definite upper limit as

                                              to the volume, depending

                                              on the shift value (see

                                              below). The Sound Blaster

                                              and the Disney Sound

                                              Source aren't quite as

                                              restricted, but still are

                                              at some high value.
 06 - 07        4, 0                          Shift value. This is the

                                              number that each byte is

                                              divided by to "scale" the

                                              volume down to a point

                                              where the PC's Internal

                                              Speaker can handle it. See

                                              the discussion on playing

                                              back digitalized sound for

                                              more details.
   Information from Sounder text files and Sound Tool help (.HLP) files.
Sound Tool File Format:
 BYTE(S)        NORMAL CONTENTS               PURPOSE/DESCRIPTION
-----------------------------------------------------------------------
 00 - 05        "SOUND", 26                   Just an identification

                                              thing. Helps a lot when

                                              you are trying to

                                              distinguish between

                                              Sounder .SND files and

                                              Sound Tool .SND files.
 08 - 11        ???                           This is the number of

                                              bytes in the sample. It is

                                              calculated as follows:
       ByteSam = Byte1 + (256 * Byte2) + (512 * Byte3) + (768 * Byte4)
 12 - 15        ???                           This points to the first

                                              byte to play in the file.

                                              It is calculated the same

                                              way as the number of bytes

                                              in the sample (see above).
 16 - 19        ???                           This points to the last

                                              byte in the sample to

                                              play. Calculated the same

                                              as above.
 20 - 21        ???                           Sampling rate of the

                                              sample. Valid values are

                                              22 KHz, 11 KHz, 7.33 , and

                                              5.5 K, but if given a

                                              number not listed above,

                                              it will be played at the

                                              closest valid sampling

                                              rate. So, 9 KHz would be

                                              played at 11 Khz. This is

                                              calculated as follows:

                                              SamRate =  Byte1 + (256 *

                                              Byte2)
 22 - 23        ???                           Bits per sample. Ex: Sound

                                              Blaster can only do 8,

                                              Sound Blaster 16 can make

                                              16. Normally, the only

                                              valid value is 0, which is

                                              the code for an 8 bit

                                              sample. Future versions of

                                              Sounder and DSOUND.DLL may

                                              allow 16 bit samples and

                                              such.
 24 - 25        ???                           Volume to play the sample

                                              back at. Note: On the PC's

                                              Internal Speaker, there is

                                              a definite upper limit as

                                              to the volume, depending

                                              on the shift value (see

                                              below). The Sound Blaster

                                              and the Disney Sound

                                              Source aren't quite as

                                              restricted, but still are

                                              at some high value.
 26 - 27        4, 0                          Shift value. This is the

                                              number that each byte is

                                              divided by to "scale" the

                                              volume down to a point

                                              where the PC's Internal

                                              Speaker can handle it. See

                                              the discussion on playing

                                              back digitalized sound for

                                              more details.
 28 - 123       ???                           This is the name of the

                                              sample. It is followed by

                                              an ASCII 0.
   Information from Sounder text files and Sound Tool help (.HLP) files.
      Whoo! That was a TON of typing. WHOA!! I just literaly spend all

   night preparing those messages for you. I believe I started it around

   12:00 am and now it's 5:00 am! Let me apologize if I made any

   mistakes in the previous messages, hard to type perfectly when your

   eye lids keep falling down <g>.
      I don't know the file format for MDI and MID files, and I don't

   think that they can be played on the internal speaker or printer port

   DACs. Sorry!
      Well, I hope I've answered all your questions, if you get anymore,

just post to me! Have fun with the new information!  
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

                     INTRODUCTION TO 3D SERIES #1

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Writer: Matthew River Knight
Have you ever played Quake and wished you could make a similar game in

Qbasic? Have you ever tried to learn how to code a 3d program in Qbasic,

only to find that there are no good tutorials out there? Yep? Well then

this tutorial is just for you! ^_^
I remember when I wanted to learn how to do 3d, it was a total nightmare.

I went to every shop I knew of in search of a book - they had books on the

subject, but they were all aimed at C programmers...there was nothing for

Qbasic coders such as myself. Next I decided to search around the internet

for a decent tutorial. I found several tutorials, but to my alarm, they were

all so complicated! I'm sure that some of you have, at some stage,

downloaded a certain 3d tutorial by Matt Bross. What a mistake that was eh?!

It is a pathetic excuse for a tutorial. It consists only of extremely 

complicated and difficult to read code, then followed by a very brief

explanation of what it does, and an even briefer explanation of how it goes

about achieving this.
In order to fill the obvious void in the QB world for a decent 3d programming

tutorial, I have decided to do a series about it right here in QBCM! We are

going to take things step-by-step, progressing from the very simplest 

aspects of 3d programming, right up to the more complicated, but extremely

fun stuff! ^_^
Don't worry if you aren't good at maths, or aren't a programming guru. I

am going to explain things in such a way that they are going to be very

easy to understand, regardless of your ability! I do however recommend that

you have at least an intermediate knowledge of Qbasic. As far as the maths

is concerned, there is a large misconception amongst the programming circles

that in order to do 3d, you have to be a genius with mathematics. Not so.

You will need to have a good knowledge of Algebra, Geometry, and Analytical

Algebra. That's it. It does help to know Trigonometry, but it is not a

necessity.
Okay, I have rambled on long enough! Let's start learning how to program

in 3d!!! To begin with, we need to know how to define a point in a 3d world.

You already know how to define a point in 2d - it's simple...you have your

X coordinate to describe the point/pixel's location across the screen, and

you have your Y coordinate to describe the point/pixel's location down the

screen. In 3d it works exactly the same way, however, we have to add another

coordinate: Z. The Z coordinate describes the depth, or in other words,

how far the point/pixel is away from the viewer. In a 3d world, the exact

center of the world is X,Y,Z = (0,0,0). So, a point that is 100 pixels

to the left of the center of the 3d world would be at (-100,0,0). A point

that is 50 pixels to the right of the center of the 3d world, 100 pixels

higher than the center of the 3d world, and 10 pixels closer to the viewer

than the center of the 3d world, would be at (-50,-100,10). All of the

points in your 3d world are collectively called the world coordinates.
Using the above method, it is easy to create a 3d world. If, for example,

you wanted a quadrilateral (such as a cube) in your 3d world, you would

compose it by defining points which are the vertices of the object. Later

on, when actually drawing the object on the screen, we connect all of the

points/pixels together by using the LINE statement. This gives us what is

called a wireframe representation of the object. But, before we can draw

our 3d objects on the screen there's some stuff you have to know - we'll

cover that at a later stage.
Once we have defined all of our world coordinates, we have to place the

camera in the 3d world. The camera (also called the eye or the viewer) is

what actually looks at the world. If you place it high above the 3d world,

then you see the world in much the same way that it would be seen from a

high tree, or a building. If you place the camera much lower down, then

you will see the 3d world from an ants point of view! The camera's position

is defined in exactly the same way as the world coordinates: you describe

the camera's position in the 3d world with X, Y, and Z coordinates. It is

important to note that the camera will ALWAYS 'look' to the center of the

3d world (0,0,0).
Now that we have defined our world coordinates, and have defined our camera

position, we have to find a way to plot the 3d world on the screen, relative

to the camera's point of view. Now the most obvious question is "how on

Earth do I plot a 3d object on a 2d surface like the screen??!!" Well, let's

take this one step at a time.
Okay, let's say we have defined a single point in a 3d world where:
x_world = 100

y_world = 20

z_world = 10
The first step in getting our 3d world onto the screen is changing these

world coordinates into what is called the camera coordinates. The camera

coordinates describe the world coordinates as they are seen from the

camera's point of view.
Now, in order to change the world coordinates into camera coordinates, we

have to use a set of mathematical formulae. "Nooooo!" I hear you say. Heheh,

don't worry, it isn't difficult at all...and I am going to explain how it

works. ^_^
Now let's think about this logically. Suppose we are in a 3d car racing

game. Our camera (which is basically the same as the person inside our

car in the game) is at (100,10,10) and is looking at the center of the 3d

world (0,0,0) (you will recall that the camera in a 3d world will always

look to the center of this world). With the camera at this position, the

center of the world is at (-100,-10,-10). From this information, it seems

that:
x_camera = x_world - camerapos_x

y_camera = y_world - camerapos_y

z_camera = z_world - camerapos_z
where:
x_camera = x coordinate of a point (camera coordinate system).

           Ditto with y_camera, and z_camera.

x_world = x coordinate of a point (world coordinate system).

          Ditto with y_world, and z_world.

camerapos_x = x coordinate, describing the position of the camera in the 3d

              world. Ditto with camerapos_y, and camerapos_z.
And guess what...those equations are actually the equations we use to

convert world coordinates into camera coordinates!!! ^_^
It is important to note that you can place the camera anywhere in the 3d

world, except for one place - you CANNOT place the camera in the center of

the 3d world (0,0,0). You can put it anywhere but there. Why? Well, since

the camera will always look to the center of the world, if the camera was

in the center of the world it would be looking at itself. Can you look at

your eyes??!! Nope, of course not (not without a mirror anyway.) So you

can't put the camera at (0,0,0). If you do put the camera in the center of

the world, then some of the mathematical formulae which we are about to

describe will not work, and the program will crash.
Okay, so now we have converted our world coordinates into camera

coordinates. But we still can't draw our 3d world/object(s) on the screen

yet. We still have points which are described by X, Y, and Z, but the PSET

and LINE statements can only draw with points defined by X and Y (which is

2d) - this is logical really...the screen is, after all, a 2d surface.
In order to draw in 3d on the screen using PSET or LINE, we have to convert

our camera coordinates (which describe the 3d world coordinates relative to

the camera's point of view) into 2d screen coordinates. How? Simple. We use

a set of mathematical formulae!!! (Do I hear groaning?! ^_^)
Once again, we have to think about the problem at hand with a bit of logic

and common sense. In real life, objects that are further away from us

look smaller than they do when you are right next to them. The principle

is the same with 3d computer graphics. For example, imagine that in our

3d world we have two points/pixels that are 10 pixels length apart. If their

Z coordinates are both decreased by 1, then the two points are each going to

move one pixel length closer to the other. This information demonstrates

the golden wisdom of every 3d programmer: "The screen coordinates could be

calculated by dividing the X and Y position through the depth (z coord-

inate)."
This shown as a formula is:
x_screen = x_camera / z_camera

y_screen = y_camera / z_camera
where:
x_screen = x coordinate of the pixel on the screen.

y_screen = y coordinate of the pixel on the screen.

x_camera, y_camera, z_camera = (see above).
However, we have several different screen modes at our disposal, and (0,0)

on the screen is actually the top left hand side of the screen, so we have

to change the formulae a little if we want the 3d object to be centered on

the screen and if we want the program to work in all screen modes. The final

set of formulae for conversion of camera coordinates to screen coordinates

is as follows:
x_screen = (x_camera / z_camera) * srx + srx / 2

y_screen = (y_camera / z_camera) * sry + sry / 2
where:
srx and sry describe the screen resolution. In SCREEN 13, srx would be

equal to 320, and sry would be equal to 200.
Another very important thing that I must mention is that if any of our

points in the 3d world go behind the camera, or in line with the camera,

then the math for projection of the camera coordinates onto the screen goes

all haywire. This is logical really. In real life, if an object is behind

you, or in line with your eyes on the side, then you cannot see it. This is

the same with 3d computer graphics, but the problem is that the computer

doesn't yet know that we must not be able to see these points, so it

attempts to use the math on them anyway, and it goes nuts!!! ;)
We'll say that points in our world coordinates that are in line with or

behind the camera are "out of range". In order to fix this problem, it is

necessary that we do a test on all of the points in our 3d world (the world

coordinates) to see if they are "out of range" and if they are, then we

have to temporarily eliminate them. When they are back in range again, then

we can put them back and have them plotted on the screen. Let's explain this

another way: if the value of the world Z coordinate of a point is equal to

camerapos_z or greater than camerapos_z then it is "out of range" and we

must eliminate it (ie. we don't draw it!) Simple eh?! Here's some code

for this:
IF x_world >= camerapos_z THEN 'Don't PSET this point!
Please note that when you are doing a 3d engine you should NEVER use PSET

do draw everything in the world. That would be terribly slow. LINE is a

much faster alternative, however, I used PSET here in order to make the

explanation easier to understand.
Well, this concludes the first entry into the INTRODUCTION TO 3D SERIES. I

hope you enjoyed it! Next issue we'll be covering 3d rotation, how to code

a 3d program in which you can 'walk' about the world, and hidden surface

removal. We'll also add some source code to help ya out! ^_^
Cya next month!  
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

                        QB TIPS, HACKS, AND TRICKS

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
-----------------

Using COM 3 and 4

-----------------
Writer: Matthew River Knight
One of the biggest reasons that we don't see many QB programs around that 

use the modem is that Qbasic is limited to using COM ports 1 and 2. The

problem with this is that these days most people have internal modems, and

most of these modems use either COM ports 3 or 4 - and Qbasic can't access

them. However, fear not, there's a way around this! ^_^ Here it is:
EXAMPLE 1: Accessing COM3 from Qbasic.
DEF SEG = 64    'Move QB segment pointer to BIOS data area.

POKE &H00,&HE8  'Change COM1 address in BIOS data area to COM3.

DEF SEG         'Return to QB's DGROUP.
'Open COM3 by issuing OPEN "COM1:" command.

OPEN "COM1:1200,N,8,1" FOR OUTPUT AS #1
PRINT #1,"ATDT844-1212"  'PRINT to COM port.
CLOSE #1           'Close COM port.
DEF SEG = 64    'Point to BIOS data area.

POKE &H00,&HF8  'Restore COM1 address in BIOS data area to COM1.

DEF SEG         'Return to DGROUP.
EXAMPLE 2: Accessing COM4 from Qbasic.
DEF SEG = 64    'Move QB segment pointer to BIOS data area.

POKE &H02,&HE8  'Change COM2 address in BIOS data area to COM4.

DEF SEG         'Return to DGROUP.
'Open COM4 by issuing OPEN "COM2:" command.

OPEN "COM2:1200,N,8,1" FOR OUTPUT AS #1
PRINT #1,"ATDT844-1212" 'PRINT to COM port.
CLOSE #1  'Close COM port.
DEF SEG = 64    'Point to BIOS data area.

POKE &H02,&HF8  'Restore COM2 address in BIOS data area to COM2.

DEF SEG         'Return to DGROUP.
---------------------

Fun with the keyboard

---------------------
Writer: Matthew River Knight
Hmmm...how about we disable all input from the keyboard??!! ^_^
Heheh, this is a really nasty trick to do to someone...you could compile the

following program and add a line to AUTOEXEC.BAT to run the proggy when the

computer is next rebooted ;)
It could also make a great addition to a security program...if the wrong

password is entered then you disable the keyboard ^_^
To disable all input from the keyboard:

DEF SEG = 64

OUT 97, 204
To re-enable input from the keyboard:

DEF SEG = 64

OUT 97, 76
As soon as the computer is rebooted, the keyboard will revert back to its

normal self. However, that can always be fixed by running the proggy again!

Heheh ;)
Last year I played this prank on my computer teacher...she went off to get

some diskettes from the stock room, so while she was away I copied this

program onto her computers hard-drive, and added a line to AUTOEXEC.BAT to

automatically run it. Heheheheheh ^_^ If you also want to try this at

school and you get caught, don't blame me! ^_^
That's all the tips, hacks, and tricks we have for ya this issue. If you

know and cool QB tips, hacks, or tricks, then please share them with us by

emailing them to me at horizonsqb@hotmail.com so I can print them in the

next issue of QBCM!!!  
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

                              BASIC MUSEUM

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Writers: Daniel P.Hudson, Jean E.Sammet, and Matthew R.Knight 
Over the last two issues of QBCM we have covered the history of raytracers/

raycasters, and the history of 3d in BASIC, however we have yet to actually

look at the history of BASIC itself. Thusly, in this month's BASIC MUSEUM,

we are going to take a brief look at how the BASIC cult began ^_^
BASIC (standing for Beginner's All Purpose Symbolic Instruction Code) is a

system developed at Dartmouth College in 1964 under the directory of

J.Kemeny and T. Kurtz. It was implemented for the G.E.225. It was meant to

be a very simple language to learn and also one that would be easy to

translate. Furthermore, the designers wished it to be a stepping-stone for

students to learn one of the more powerful languages of that time such as

FORTRAN or ALGOL.
Bill Gates and Paul Allen had something different in mind. In the 1970's

when M.I.T.S.'s Altair personal computer was being conceived Allen convinced

Gates to help him develop a BASIC language for it. When M.I.T.S. answered

with interest, the future of BASIC and the PC began. Gates was attending

Harvard at the time and Allen was a Honeywell employee. Allen and Gates

licensed their BASIC to M.I.T.S. for the Altair. This version took a total

of 4K memory including the code and data used for source code!
Gates and Allen then ported BASIC to other various platforms and moved back

to their hometown of Seattle where they had attended grade school together.

It was at this time that the Microsoft Corporation began it's reign in the

PC world. By the late 70's, BASIC had been ported to platforms such as the

Apple, Commodore and Atari computers and now it was time for Bill Gates's

DOS which came with a BASIC interpreter. 



The Commodore 64 was probably the most popular home-computer throughout the 

80's. Almost every game ever made for the machine was coded with a mixture 

of BASIC and ASM.



The IBM-DOS version of this interpreter became known as BASICA, and at the

time IBM was in major competition with clones so it was setup to require

the BIOS distributed with IBM computers. The version distributed with

MS-DOS was GW-BASIC and ran on any machine that could run DOS. There were

no differences between BASICA and GW-BASIC which seems to make IBM's idea

useless.
Microsoft realized just how popular their BASIC interpreter was and decided

to distribute a compiler so users could code programs that ran without an

interpreter. QuickBASIC was the solution Microsoft came up with. It was

distributed on through the years until version 4.5. At this time Microsoft

decided to release a product with more kick and started distributing

PDS BASIC (Professional Development System) and ended it with version 7.1

(Also called QuickBASIC Extended), PDS was a short lived idea and was not

followed through to its true capabilities. [Though it was an improvement

over QB4.5]. Microsoft got hooked on GUI's and started Visual BASIC both a

DOS and WIN version. The DOS version was ended at 1.0 with a professional

update. Differences between VB for DOS and QB are not as much as one might

think, in fact VB still compiles QB4.5 code and the professional edition

will compile PDS7.1 Code. One last thing: PDS will compile to true OS/2 

code, VB-DOS Pro/std and QB4.5 will not.
BASIC is still in a state of change and progression. Visual BASIC is still

being updated and improved, and a number of other variants of this great

language are also being churned out from various sources. Although many

people may currently say that the future of BASIC lies within the Windows

OS, it is likely that this is not so. Linux has grown enormously in

popularity over the past few years, and is continuing to do so. It is more

than likely that in a few years Linux will be the OS of choice. It is

difficult to say exactly where the future of BASIC lies, however, the

obvious pro's of the language, along with its vast user base who's love of

the language exceeds a hundred fold what it visible with other languages,

should be more than enough to keep BASIC as one of the leading programming

languages for decades to come. 
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

                                  REVIEWS

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
We have three programs for review this month. So check out these reviews

to see if they're da bomb or a bomb ^_^ If you have a Qbasic program that

you would like us to review, then please email me at horizonsqb@hotmail.com

and tell me the URL of the website where I can get the program from. Please

DO NOT email your program to me!
-------------------------------------------------

Program: Botwarz

Program type: Game

Developer: Psycorey

Minimum system: 286, 640KB RAM

Recommended: As above

Available at: http://www.angelfire.com/nh/elfingo

-------------------------------------------------
You own a copy of QuickBASIC. You walk up to me in the street and prod me

gently but firmly in the chest with a well manicured forefinger. "Hey

fella," you demand aggressively, "which is the best two player shooter

currently available on God's own recently resurrected programming platform?"

I would have no hesitation in recommending several releases to you, The

Labyrinth, Space War, even my own Qbasic Tank Commander II (at a push) but

crucially, I would stop short of urging anyone to go out and spend a minute

downloading Botwarz.
Botwarz, as the name suggests, is a two player game in which you and a

friend (or foe) take the role of robots, and go around trying to shoot

eachother up. There is also a one player mode, however, it really isn't

worth playing, and the two player mode is far more enjoyable. One of the

coolest things about this game is the number of different weapons you have

at your disposal. In addition to that, you have a wide selection of

different robots to choose from, which makes the game a lot more

interesting than it would otherwise have been.
The graphics are of a VERY low standard. Although the game uses SCREEN 13,

there is no shading, no form of lighting in any way, and it is impossible

to see what any of the graphics are actually supposed to represent. There is

no background graphics either, just a plain black screen, which is very

boring indeed. The animation, while fast and flicker free, shows absolutely

no effort whatsoever. Just static bots sliding across the screen...yawn! As

far as the sound department is concerned, well, I don't really know. There

are a number of WAV's included with the game, but I couldn't get the

sound to work on my computer, so I can't really say. It does seem pretty

odd, I must confess, that the sound never worked...I have a Sound Blaster

16 sound card...that's pretty much standard in the computer world...
                          
And this, my friend, is the graphics...need I really say more?



Okay, so now we know the graphics and sound aren't any good...how about the

gameplay? Argh, I wish you hadn't asked! Let's start with the one player

mode...well, as I have said before, it isn't really worth playing. There's

no plot, no mission, no real levels...so it's all pretty pointless. The two

player mode is a little better...at least it is worth playing, but the

controls are unwieldy, and the poor graphics, and in my case lack of sound,

makes even the two player game a torture to play. And anyway, there's many

two player Qbasic games out there, much higher in quality...so why bother

with Botwarz in the first place?
I must admit, I hate to give programmers bad reviews on their games, and I

always try to like something about the game, but Botwarz was depressing

from the very beginning...sigh...you can't say I didn't try to like it :(
QBCM VERDICT: 12%
---------------------------------------

Program: Diamond Fighter IV

Program type: Game

Developer: Master Creating

Minimum system: 486DX2/66, 4MB RAM

Recommended: Pentium 100, 4MB RAM

Available at: http://master-creating.de

---------------------------------------
Master Creating is a fine old development company who've been turning out

classic games since the days of the Spectrum and Commodore 64. Shadow of

Power was theirs, and now they're back with Diamond Fighter IV. The Diamond

Fighter series goes back a long way. The first episode in the series was

in fact created on a Commodore 64 almost a decade ago!
Diamond Fighter is an interesting piece of work in the light that it's a

puzzle game - a genre that has been subject to much neglect in the QB world

since its very birth. The game throws you into futuristic USA, where the

aim of the game is to complete each of the various levels in order to

complete the game. Completing a level is easier said than done! It involves

solving a sequence of puzzles in order to get to various parts of the level,

whilst collecting all of the diamonds found there. Once you have collected

each diamond, then you may proceed to the next level. There are many levels

in the game (each state in the USA represents a level) and they are all

nicely varied and have been realised with much care and imagination.
The graphics in DF are of an exceptional standard. Most of the graphics is

in SVGA, and surprisingly, it runs at an acceptable pace on even the most

humble of systems. All of the artwork is nicely detailed, and there's also

some nice effects such as flashing lights, various lighting effects, and

many others, which look very cool indeed. There's one effect where the

aliens sort of melt into a fleshy pile on the floor, which I found pretty

amusing...if not disgusting! As would be expected with a game from Master

Creating, the sound effects are utterly fabulous. There's also a bit of

speach now and again, which is all in German, but has been nicely done. My

only reservation is that there's no music in the game. I usually find that

some catchy tunes add immeasurably to the enjoyment derived from a game.
Diamond Fighter IV is an addictive game, and has been produced with quality

in mind. You may find it difficult to figure the game out at first, however,

it shouldn't take you long, and once you have mastered the basics, this game

will be a big favourite in your collection. Highly recommended.
QBCM VERDICT: 93%
---------------------------------------------------------------

Program: Novascript 1.0 beta

Program type: Programming language

Developer: CarterSoft

Minimum system: 386, 640KB RAM

Recommended: As above, or better

Available at: http://www.cole_carter.tripod.com/novascript1.zip

---------------------------------------------------------------
Yet another Qbasic contender steps into the ring. Take your places

gentlemen. ^_^
Qbasic is, politely spoken, starting to get a bit, well, old, and sooner or

later we are going to going to either need a new version, or convert to

some other variant of BASIC. Many are in production right now, and while

the Qbasic world merrily twiddles its thumbs waiting for Nekrophidius'

QuickPower, Novascript intends to dash swiftly into the gap.
As Qbasic contenders go, NS scores and fails on various points. It scores

because it is quite a bit faster than Qbasic in every respect, 386+

registers and opcodes are used, and users of the language will be able to

get help easily since NS's creator can easily be contacted through email

or via #qbchat. However, NS fails on various points too. For one, NS cannot

be called a true variant of BASIC. The code resembles C in many ways, and

for this reason, it's unlikely that QB users will want to convert to it.

Here's some example NS code serving as proof of its similarities to C:
-- Press Shift + F5 to execute this example

-- Let's the user type in musical notes

-- 8:14AM  4-3-00 

-- You have a royalty-free right to use, modify, reproduce

-- and distribute the sample applications  provided with

-- Novascript for MS-DOS (and/or any modified version)

-- in any way you find useful, provided that you agree that

-- CarterSoft has no warranty, obligations or liability for

-- any of the sample applications or.

Declare; music$

Begin{

Printw; Type in some musical notes

itext = Notes...

input music$

!notes$ music$

printw; Thank You for playing Music

end }
The way in which the code is used is also very inconsistent which makes the

language difficult to learn. Another problem is that there is no real

syntax or anything in NS for many of the commands. For example, to use the

LINE statement, you first have to define variables for drawing the line

from one point to the other, for the color of the line, etc. Here's a bit

of example code:
-- =============================

-- This Sample graphic examples

-- (c) 2000 CarterSoft 

-- =============================

Begin{

cls

scrn 2

Printw; Circle

C1# 320

C2# 100

C3# 200

delay

cls

scrn 13

Printw; Line

L1# 0 

L2# 100

L3# 319

L4# 100

deLay

cls

scrn 1

Printw; Triangle

Pict C2

Pict F60 L120 E60

Pict BD30

Pict P1,2

delay

end }
Lastly, the language is not as versatile as Qbasic, and the user doesn't

have quite as much power, or control over the machine. However, it's

more than likely that the missing features will be there in the full

version. The IDE itself is very much like the one employed by Qbasic. It

is pleasing to use, and easy to master. There is also some fairly good

documentation on the language, however, the online help feature has yet to

be implemented.
Well, NS 1.0 beta is far from complete, so I'll, for the most part, reserve

my judgement until the final release. The speed of NS, and the high quality

IDE, makes NS a promising project, and one certainly worth keeping an eye

on. Be sure to check it out!
QBCM VERDICT: 72% 
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

                              COMPETITIONS

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
---------------------------

QBCM mini game of the month

---------------------------
This is a competition for the best Qbasic game under 40KB ZIPed. The best

game I recieve will be included with the next issue of QBCM! In order to

enter this competition, simply email your game to me at horizonsqb@hotmail.com

This month's winner is Joe King for his little game, Toadman. Congrats! It

has been included with this issue of QBCM...it's TOADMAN.ZIP!
Those of you who entered your games and didn't win, don't worry. They are

automatically re-entered into the competition for the following month, so

who know...maybe you will be the winner next month! ^_^
-------------------------

QBCM website of the month

-------------------------
This is a competition for the best website dedicated to Qbasic. To enter,

simply email the URL of your site to me at horizonsqb@hotmail.com. This

month the winning site is Chris Charabaruk's site: http://picksoft.zext.net

Congratulations! 
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-

                              CLOSING WORDS

-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
I must say that I thoroughly enjoyed compiling this issue of QBCM. I hope

it has been just as much fun for you to read it! It really amazes me how

much this magazine has grown over the past three months. I certainly have

no doubt that it will continue to do so!
Once again, please email any articles, letters, etc to me at

horizonsqb@hotmail.com. Any input you can provide will be greatly

appreciated. :)
Thank you for reading issue 3 of QBCM! Keep codin' in QB!
Cya next month!!! ^_^
-Matthew River Knight