Developing for Commander X16 in Prog8 – Part 2

Prog8 source code files are saved with the extension .p8

A simple setup for your program will be structured as such:

main {
    sub start() {
        ; Add your code here...
    }
}

You can name the file whatever.p8 you want. The main file will need a ‘main’ code block along with a ‘start()’ codeblock. Comments are denoted with a semicolon ; and longer comments are /* Between slash and stars */

Let’s start with the good old “Hello world!” beginners code:

Prog8 comes with a lot of useful libraries built-in. When you compile and assemble the code, only the parts you use will be added. This keeps the code neat, tidy and small. First, we’ll import the text library and use it thus:

%import textio
%zeropage basicsafe

main {
    sub start() {
        txt.print("hello world!\n")
    }
}

When you build and run this code you should see:

An explanation for the ‘zeropage basicsafe’ directive from the Prog8 website:

It is the most restricted mode; only use the handful ‘free’ addresses in the ZP, and don’t touch change anything else. This allows full use of BASIC and Kernal ROM routines including default IRQs during normal system operation. When the program exits, it simply returns to the BASIC ready prompt.

This is exactly what we want to start. You will not necessarily use this in future programming, but it returns us safely to the BASIC READY prompt.

There are some built-in useful text subroutines. These are self-explanatory:

clear_screen(), cls() – clear screen; home() – move cursor to top-left, nl() – print newline; spc() – print a space; bell() – make a beep; column(X) – set column to print at X; row(Y) – set row to print at Y; fill_screen(A,C) – fill the screen with character A in colour C; color(C) – change color for characters to print to C; setchr(X,Y,C) – print character C at X,Y locations. You can find more in the Prog8 library. Play around with them for yourself to see what you can do!

Let’s make some beautiful music (err Sound FX) together!

You will need to import the psg library and then let’s make a sound:

%import psg
%zeropage basicsafe

main {
    sub start() {
        psg.voice(1, psg.LEFT|psg.RIGHT, 63, psg.NOISE, 0)
        psg.freq(1, 846)
        psg.envelope(1, 63, 250, 0, 2)

        sys.wait(20)
        psg.silent()
    }
}

New stuff: We use sys.wait(20) – wait approximately the given number of jiffies (1/60th seconds). You do not need to import the system library as it is imported by default. ’20’ is sufficient here. We do that for the sound to happen and then use silent() to turn it off again, otherwise it just keeps playing and blowing out your eardrums! 😀

The psg library: Contains a simple abstraction for the Vera’s PSG (programmable sound generator) to play simple waveforms. Here, we’re using the NOISE waveform on voice 1 and setting it to play in stereo (in LEFT and RIGHT). The voice parameters are: voice#, channel, volume, waveform and pulse-width (not used for noise). freq sets the frequency to play on voice #1. The voices you can use are 0-15 inclusive. Waveform types are: PULSE, SAWTOOTH, TRIANGLE and NOISE. Channels are self-evident. envelope sets the Attack, Decay, Sustain and Release parameters on Voice #1 again here.

Some other code to try:

%import psg
%import math
%zeropage basicsafe

main {
    sub start() {
        psg.voice(1, psg.LEFT|psg.RIGHT, 63, psg.TRIANGLE, 0)
        uword f = (math.rndw() % 5000) + 6000
        psg.freq(1, f)
        psg.envelope(1, 63, 250, 1, 18)

        sys.wait(20)
        psg.silent()
    }
}

We’ve thrown in another interesting function here. First, we import the math library so we can pick a random number for the frequency. f is a random number from 6000-11000 (from 6000 and up to 6000+5000). We’re using the TRIANGLE waveform for a ‘ping’ sound. uword defines the f variable as a 16-bit size (0-65535) unsigned variable. ‘unsigned’ means all positive integers and no negatives. If you had set the variable to word then it would, by default, be -32768 to +32767. I won’t go into the different variable types. You can read all about them in the previous link and many places on the internet. The rest is covered above.

        psg.voice(1, psg.LEFT|psg.RIGHT, 63, psg.SAWTOOTH, 0)
        uword f = (math.rndw() % 500) + 600
        psg.freq(1, f)
        psg.envelope(100, 63, 250, 100, 18)

Rather than including all the code each time, just replace the parts I’ve shown above.

        psg.voice(1, psg.LEFT|psg.RIGHT, 63, psg.SAWTOOTH, 50)
        uword f = (math.rndw() % 500) + 600
        psg.freq(1, f)
        psg.envelope(100, 63, 250, 100, 18)

Change just this line from the above code:

       psg.voice(1, psg.LEFT|psg.RIGHT, 63, psg.PULSE, 50)

I recommend playing around with different values in order to discover things yourself. It can be a lot of fun!

That should give you enough stuff to play around with until Part 3 is ready!

Thanks to @irmen for their Rock Runner github code referenced above.




Comments are Closed

© 2024: Blue Bilby | GREEN EYE Theme by: D5 Creation | Powered by: WordPress