Jump to content
IGNORED

From Basic to Forth - Issue 1 - Sound


cas

Recommended Posts

Hello,

 

this is a new "Basic to Forth" course. I did something similar already last year in the ABBUC Forum, I'll start it here in english language.

 

The course will present 2-3 little code snippets each week, explaining how it is done in BASIC and then how to do the same stuff in Forth, using VolksForth as an example.

 

I'll start by publishing the issues I already did in the ABBUC Forum, and then I'll continue with new issue in both Forums (German version in the ABBUC Forum, English one here).

 

The course is using Atari 8Bit specific features, so it is only partially portable to other platforms.

 

 

 

Issue 1 - Sound

 

This time we cover sounds. I have found the Basic Program below to which creates a hoover sound.

 

10 REM European hooter
15 LOW=57:HIGH=45:P=45
20 FOR AGAIN=1 TO 20
30 SOUND 0,P,10,14
40 FOR WAIT = 1 TO 180: NEXT WAIT
50 P=LOW:LOW=HIGH:HIGH=P
60 NEXT AGAIN
70 SOUND 0,0,0,0
80 END

 

In VolksFORTH there is no build in SOUND command, so we have to build one that is compatible with the BASIC Sound command.

 

\ Atari 8bit Sound Command

$D200 CONSTANT AUDBASE

: SOUND ( CH# FREQ DIST VOL -- ) 
  SWAP $10 * + ROT DUP + AUDBASE + ROT OVER C! 1+ C!;

 

With that new Word SOUND we can recreate the "hoover" sound in Forth.

 

: hoover
 57 54  ( Sound values for hoover sound )
 20 0 DO 
 OVER
 0 SWAP 10 14 SOUND
 500 0 DO LOOP ( delay loop )
 SWAP  ( change sounds )
 LOOP
 0 0 0 0 SOUND;

 

The BASIC Program uses 5 variables (LOW, HIGH, P, AGAIN, WAIT), the Forth version works without any variable declaration, all values are passed on the stack. This is one reason why Forth is memory efficient.

Link to comment
Share on other sites

That's fascinating. I look forward for future installments of VolksFORTH tutorial you will provide. It is so easier to learn it this way. Thank you! I think more people will start digging deeply in the secrets of this mystical language ;)

 

What did you understand from the Forth code presented?

 

What does this line do?

 

SWAP $10 * + ROT DUP + AUDBASE + ROT OVER C! 1+ C!;

 

I gleaned that loops are inverted, as pretty much everything in Forth is in RPN.

 

I certainly laud Carsten's efforts, but unless one already *knew* Forth, I really doubt that the above line means much of anything.

 

-Larry

Link to comment
Share on other sites

That's fascinating. I look forward for future installments of VolksFORTH tutorial you will provide. It is so easier to learn it this way. Thank you! I think more people will start digging deeply in the secrets of this mystical language ;)

 

What did you understand from the Forth code presented?

 

What does this line do?

 

SWAP $10 * + ROT DUP + AUDBASE + ROT OVER C! 1+ C!;

 

I gleaned that loops are inverted, as pretty much everything in Forth is in RPN.

 

I certainly laud Carsten's efforts, but unless one already *knew* Forth, I really doubt that the above line means much of anything.

 

-Larry

 

Hello Larry,

 

I agree. The Sound Word needs some explanation. It builds the same command as is available in Basic. THe content of this word in detail

 

CH# = Pokey Sound Channel 0-3

FREQ - Frequency

DIST - distortion

VAL - Sound volume

 

The comment show what is on the Stack

 

: SOUND ( CH# FREQ DIST VOL -- )
  SWAP  ( CH# FREQ VOL DIST -- we swap volume and distortion )
  $10	 ( CH# FREQ VOL DIST $10 -- hexadecimal $10 or decimal 16 on the stack )
  *		( CH# FREQ VOL DIST*$10 -- distortion is now multiplied by 16 )
  +	   ( CH# FREQ VOL+DIST*$10 -- volume and distortion are added together )
  ROT	( FREQ VOL+DIST*$10 CH# -- we rotate the topmost 3 stack items, brining CH# on the top )
  DUP	( FREQ VOL+DIST*$10 CH# CH# -- we duplicate the topmost stack item, the Channel )
  +	   ( FREQ VOL+DIST*$10 CH#+CH# -- the Pokey Frequency Registers are two bytes apart, so we multiply the channel by 2 by adding the channel values )
  AUDBASE  ( FREQ VOL+DIST*$10 CH#*2 $D200 -- we put the constant AUDBASE on the Stack, value is $D200, the first pokey frequency register )
  +			 ( FREQ VOL+DIST*$10 CH#*2+$D200 -- we add the channel to AUDBASE )
  ROT		  ( VOL+DIST*$10 CH#*2+$D200 FREQ -- we rotate the topmost 3 Stackitems, bringing the Frequency on top )
  OVER		( VOL+DIST*$20 CH#*2+$D200 FREQ CH#*2+$D200 -- OVER copies the 2nd Stackitem on the Top of the Stack )
  C!			 ( VOL+DIST*$20 CH#*2+$D200 -- we store [think POKE] the Frequency value in the Pokey Frequency register )
  1+			( VOL+DIST*$20 CH#*2+$D200+1 -- we increment the topmosat stackvalue, which points now on the register for volume and distortion )
  C!			 ( -- we store volume and distortion in the Pokeys volume and distortion register )
 ;			   ( end of definition of SOUND word )

 

And now the same stuff with real values for the command 0 54 10 14 SOUND

 

: SOUND ( 0 54 10 14 -- )
  SWAP  ( 0 54 14 10 -- we swap volume and distortion )
  $10	 ( 0 54 14 10 16 -- hexadecimal $10 or decimal 16 on the stack )
  *		( 0 54 14 160 -- distortion is now multiplied by 16 )
  +	   ( 0 54 174 -- volume and distortion are added together )
  ROT	( 54 174 0 -- we rotate the topmost 3 stack items, brining CH# on the top )
  DUP	( 54 174 0 0 -- we duplicate the topmost stack item, the Channel )
  +	   ( 54 174 0 -- the Pokey Frequency Registers are two bytes apart, so we multiply the channel by 2 by adding the channel values )
  AUDBASE  ( 54 174 0 $D200 -- we put the constant AUDBASE on the Stack, value is $D200, the first pokey frequency register )
  +			 ( 54 174 $D200 -- we add the channel to AUDBASE )
  ROT		  ( 174 $D200 54 -- we rotate the topmost 3 Stackitems, bringing the Frequency on top )
  OVER		( 174 $D200 54 $D200 -- OVER copies the 2nd Stackitem on the Top of the Stack )
  C!			 ( 174 $D200 -- we store [think POKE] the Frequency value 64 in the Pokey Frequency register $D200 )
  1+			( 174 $D201 -- we increment the topmosat stackvalue, which points now on the register for volume and distortion )
  C!			 ( -- we store volume and distortion 174 in the Pokeys volume and distortion register $D201 )
 ;			   ( end of definition of SOUND word )

Link to comment
Share on other sites

I didn't have a clue what the Forth code was doing either. :) Whoever invented RPN needed more friends as a kid, but I guess I understand why he didn't have that many. :D

 

It takes some time to start Thinking in Forth, but then programming is more pleasure (even in other languages like Java, Assembler or C), as programs become more modular, compact and reusable.

 

People who learn Forth as their first programming language (I know a teacher who does Forth programming of robots in undergraduate school) find Forth and RPN quite natural.

 

Only people that have adapted their brains to Algol type languages find it difficult (It took me 2-3 years, but it was worth it). Same effect applies to LISP.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...