Shop OBEX P1 Docs P2 Docs Learn Events
A retromachine Basic interpreter [beta] - Page 5 — Parallax Forums

A retromachine Basic interpreter [beta]

12357

Comments

  • pik33pik33 Posts: 2,387
    edited 2023-08-23 10:17

    0.24:

    Basic math functions added : cos, tan, atn, asin, acos, sqr (sin was already there)
    8-bit Atari style command shortcuts added
    'mode' command can be now used with text names instead of numbers


  • pik33pik33 Posts: 2,387
    edited 2023-08-23 12:43

    After adding these Atari type shortcut I still didn't feel "at home". Atari Basic doesn't require any spaces after such commands, the dot is sufficient to separate it from the next token... corrected now.

    An example of shortcuts abusing:

    10 m.st:cursor off:mouse off:cls
    20 f.i=0 to 270 st. 10
    30 pl.377,152+i:dr.377+i,422:b.200+10*i,100:pl.377+i,152:dr.647,i+152
    40 n.i
    90 c.rnd(256):fi.477,252,rnd(256),getpixel(477,252):fc.512,288,40
    100 f.i=270 to 0 st. -10
    110 pl.377,152+i:dr.377+i,422:b.200+10*i,100:pl.377+i,152:dr.647,i+152
    120 n.i
    130 c.rnd(256):fi.477,252,rnd(256),getpixel(477,252):fc.512,288,40
    140 g.20
    

    The result (it continuously plots and beeps changing colors):

  • pik33pik33 Posts: 2,387
    edited 2023-08-23 19:39

    Added deg (switches trigonometry to 360 degree system), rad ( switches trigonometry to radians) and int (gets anything on input, returns integer on output)
    Default trigonometry unit is now radian.
    After that, this Atari Basic program

    100 SX=144:SY=56:SZ=64:CX=320:CY=192
    110 C1=2.2*SY:C2=1.6*SY
    120 DIM RR(CX)
    130 FOR I=0 TO CX:RR(I)=CY:NEXT I
    140 GRAPHICS 8+16:SETCOLOR 2,0,0:COLOR 1
    150 CX=CX*0.5:CY=CY*0.46875:FX=SX/64:FZ=SZ/64
    160 XF=4.71238905/SX
    170 FOR ZI=64 TO -64 STEP -1
    180   ZT=ZI*FX:ZS=ZT*ZT
    190   XL=INT(SQR(SX*SX-ZS)+0.5)
    200   ZX=ZI*FZ+CX:ZY=CY+ZI*FZ
    210   FOR XI=0 TO XL
    220     A=SIN(SQR(XI*XI+ZS)*XF)
    230     Y1=ZY-A*(C1-C2*A*A)
    240     X1=XI+ZX
    250     IF RR(X1)>Y1 THEN RR(X1)=Y1:PLOT X1,Y1
    260     X1=ZX-XI
    270     IF RR(X1)>Y1 THEN RR(X1)=Y1:PLOT X1,Y1
    280   NEXT XI
    290 NEXT ZI
    

    runs with only 2 changes needed:

    120 DIM RR(321) - as my interpreter cannot DIM at the runtime, and I have DIM parameter equals number of elements and not the last indes
    140 CLS - as I have no graphics 8+16 and setcolor (setcolor will be added). The system is already in the graphics mode so only clear the screen

    Of course the plot that fills the Atari 8-bit screen is much smaller - 1024x576 insted of 320x192


    4.8 seconds on a P2
    Started measurement on the Atari... this will be much longer. 6502 at 1.7 MHz instead of P2 at 340 MHz...
    ... >52 minutes.

  • RaymanRayman Posts: 14,754

    That is a cool demo.
    Can you do DIM RR(CX+1)? Is CX treated as variable or constant?

  • pik33pik33 Posts: 2,387

    It cannot have expressions as a DIM parameter, only numbers are allowed here in the current version. This is because DIM is done while precompliling, and not while running, and expressions values are not known yet.
    To allow expressions in DIM i have to move it to the runtime. That may be a complex task and it needs a proper memory manager.

  • pik33pik33 Posts: 2,387

    This Basic needed a proper audio subsystem and that means I had to upgrade my audio driver.

    Now it can not only play samples, but also does envelopes.

    The driver became an universal 8-channel audio driver that can behave like Amiga's Paula using its 3.5 MHz sample rate/period system, but it can also use a standard phase accumulator model and, with reduced to ~1.3 MHz sample rate, it can use low noise PWM DAC mode
    The envelopes are also sampled and can have up to 1024 16-bit points. The values between points are interpolated at every sample.
    The mailbox for the driver had to be extended to 16 longs: 4 new longs are now used for envelopes, 4 are unused.

    Having the upgraded audio driver I added 3 new instructions to the interpreter: defsnd, defenv and play - alias sound, shortcut so. for partial Atari 8 Basic compatibility.
    Defsnd seems to be finished. It has several modes:

    defsnd channel, "filename" : loadd the waveform from PC Softsynth type .s2 file. This file has a 16-bytes header that can be simply skipped, and then 1024, 16-bit signed samples that defines one period of a waveform. I have several such files so I added this option. PC Softsynth is a program that interprets music files from Atari Softsynth, the program for 8-bit Atari written in Germany in 1985. I wrote this several years ago. Unfinished, but plays.

    defsnd channel, harmonic,harmonic... (up to 16) synthesizes the waveform from given amount of harmonics

    defsnd channel, negative number, negative number - these 2 parameters are coefficients for even and odd harmonics, so defsnd 0,0.5,0.3 will use 1,0.5,0.3,0.25,0.09,0.125,0.003 (up to 16th harmonic)

    defenv is not finished yet. The only mode that now works is defenv "filename.h2". that loads 256-point envelope from PC Softsynth .h2 file
    To do is 4-parameter ADSR mode and 8-parameter Yamaha DX7 style with R1/L1..R4/L4

    Play is also not yet finished. As it is now it gets up to 5 parameters: channel, frequency, waveform, volume and envelope. Waveforms and envelopes have to be defined earlier by defsnd/defenv. It plays as expected, but it needs to be refined and simplified. A good example is an Atari Sorfsynth's MASIC (Music BASIC) syntax that can be very simple while giving a lot of control. The ultimate goal is to enable this Basic to play these tunes, after simple conversion process. Here are PC Softsynth examples:

    http://eksperymenty.edu.pl/images/mp3/opswiata1.mp3
    http://eksperymenty.edu.pl/images/mp3/wodo.mp3

    Atari 8 originals look like this


    I pushed the current version to Github with /media directory that contains these .s2 adn .h2 files. The /media has to be copied to the SD to be accessible by the interpreter. A flash filesystem can be convenient to keep this kind of stuff.

  • pik33pik33 Posts: 2,387
    edited 2023-08-26 21:57

    0.25:

    Math function added : deg, rad, int
    First version of my overengineered audio subsystem(tm) now works.


    Audio system
    ------------
    
    The P2 Retromachine Basic has an 8-channel audio generator that plays sampled waveforms. 
    Every audio channel can play a sound that has its frequency, volume, waveform, envelope, length (=time of playing), wait after command, stereo position ('pan') and sustain point.
    It has also 8 sets of these parameters that can be assigned to any audio channel.
    
    At the start, and after 'new' command these sets are initialized as:
    - waveforms: 0 - sine, 1 - triangle, 2 - sawtooth, 3 - pulse, 12.5%, 4 - square, 5 - pulse, 25%, 6 - Atari Pokey waveform 12, 7 - Atari Pokey waveform 2
      Use Atari Pokey waveforms at low frequencies, or aliasing will occur.
    
    - envelopes: 0: instant attack, linear release, 1: instant attack, exponential release, 2: instant attack, long sustain, instant release,
                 3: smooth both ends, 4: slow linear attack, instant release, 5: slow attack as in 4, smooth release, 6: triangle wave, 7: "classic ADSR"
    - all lengths are set to 1 (second), delays to 0, stereo position to center, volumes to 4.0, that's about 1/4 of maximum to avoid clipping, and sustain point to 255 (=no sustain)
    - every audio channels gets the waveform and envelope the same number as the channel
    
    To play the sound, there is 'play' instruction that has 0 to 9 parameters. For parameters that aren't provided, defaults will be used. If a parameter is provided, it becomes a new default. 
    The negative numbers will be ignored and defaults used instead except pan, that has range from -1.0 to 1.0. To ignore it, use less than -1
    
    The syntax is: play channel, frequency, volume, waveform, envelope, length, delay, pan, sustain
    
    Channel is the integer number from 0 to 7
    Frequency is float, in Hz. The resolution is ~0.25 Hz, the effective sample rate is 65820 Hz
    Volume is a float from 0 to 16.384
    Waveform is an integer number from 0 to 8. 0..7 selects one of predefined waveforms (as described above, if not changed by the user, see below). 8 is noise
    Envelope is an integer number from 0 to 8. 0..7 selects one of predefined waveforms (as described above, if not changed by the user, see below). 
    8 is no envelope, the sound will not stop until next play command.
    Length is a float, and it is the time in seconds for the sound to play
    Delay is integer, the time in ms, that the play instruction will wait as if waitms was added at the end
    Pan is a float in range -1 .0 to 1.0,  -1 is left, 1 is right
    Sustain is the sustain point needed to play an instrument using the keyboard. The sound will stay at the sustain volume until released. 
    Setting the sustain point  < 255 will cause the envelope to stop there. To end playing, there is the command 'release' channel. The envelope will then continue to the end.
    
    Envelopes and waveforms can be redefined.
    
    'defsnd' defines the waveform at given slot from 0 to 7. The syntax is:
    
    defsnd slot, "filename" - loads the file in /media/s directory. This is PC-Softsynth type .s2 file that has 16 bytes of a header and 1024 16-bit signed samples that define one wave period.
    The interpreter doesn't check the header, it simply loads 1024 words from the offset #16, so the user can deefine anything and save it in such a file
    defsnd slot, harmonic,harmonic... (up to 16 of them) synthesizes the waveform from harmonics
    defsnd slot, negative number,number also synthesizes the wave from harmonics, but these numbers are dampening coefficients for even and odd harmonics
    
    'defenv' defines the envelope.
    
    defenv slot, filename loads the file in /media/h directory. This is PC-Softsynth type .h2 file, that has 16 bytes of header and 256 unsigned 8-bit samples
    defenv slot,a,d,s,r defines standard ADSR envelope. a,d and r can be anything that is not negative, s should be a float in range 0.0..1.0
    
    Setting ADSR envelope will also compute its sustain point that can be retrieved by getenvsustain(slot)
    
    While the interpreter remembers all parameters from a previous play command, there is a set of commands to change them individually and then simply use play channel, freq only
    These are setenv, setlen, setpan, setrvol, setwave and setsustain. They all have syntax setxxx(channel,parameter)
    

    As 'play' command remembers all these params, to play a melody with the same parameters only 'play channel,freq' is needed after they are set. I will try to make some examples. I also want to define note constants for making playing easier
    'defsnd' and 'defenv' can also get a pointer to an array of samples, but I have no "addr" or "varptr" implemented yet to allow this to be usable. "Peek", "poke" and "addr" will be added in the next iteration.

    There is also sound command, with so. abbreviation, that now is only alias for 'play' but I added it for 8-bit Atari Basic compatibility so it is intended to use Atari 8 syntax and play something as similar as possible with this audio system.

  • pik33pik33 Posts: 2,387
    edited 2023-08-26 22:01

    This program plays random, pentatonic melodies while changing waveforms and stereo position and printing the frequencies:

    10 dim n(6) : n(0)=261.63 : n(1)=293.67 : n(2)=349.23 : n(3)=392.00 : n(4)=440.00 : n(5)=523.25
    20 r=rnd(6)
    30 q=(q+1) mod 7
    40 if q=6 then qq=(qq+1) mod 2 : setdelay 0,400 : else setdelay 0,200
    42 play 0,n(r)
    45 setpan 0,0.25-qq/2 : w=2+2*qq
    47 setwave 0,w
    50 ?n(r), 
    60 goto 20
    
  • Maybe the command should be TONE or something. PLAY I think is more usually an MML player (which I guess is a good next step for retro BASIC themed audio nonsense)

  • pik33pik33 Posts: 2,387

    I looked at this MML player stuff and it is somewhat similar to my audio nonsense, that is inspired by Atari Softsynth. The program was made in 1985 in Germany: here is the original instruction, that has German characters encoded in a standard I don't know, so I cannot open it in anything I have to see the proper German text. We had the same problem in Poland: until Unicode, there were at least 7 different standard of coding these extra characters (and this means I use yet another one in my ST font definition where I crammed non-standard letters at codes <32 to fit all in 7 bits.

  • pik33pik33 Posts: 2,387

    Note names added. They starts with #

    play 1,  #c4
    play 1, #c#4
    

    and they are internally convetred to floats so they may be used in other commands and expressions:

    print (#c4+100)

    returns 361.63

    Names are #c, #c#, #d, #d#, #e, #f, #f#, #g,, #g#, #a,, #a#, #b, #h

    About #b and #h:

    In Poland, Germany and maybe several other countries, the sound that is a half tone lower than C is called "H". "B" is a sound that is a full tone lower than C
    In USA, the sound that is a half tone lower than C is called "B"

    I left "H" for Atari Softsynth compatibility, and added "B" as an alias for H. Softsynth doesn't use B, it uses A# instead.

  • pik33pik33 Posts: 2,387
    edited 2023-09-09 13:53

    Added : poke, lpoke, dpoke, peek, lpeek, dpeek, fre, getnotevalue.

    Poke/peek family works for the full memory space: if address<$80000, HUB is used, else PSRAM is used. To access first 512k of the PSRAM< use addresses >$2_000_000: the PSRAM driver wraps around the end of the memory.
    fre returns the free Basic usable memory between program top (goes up while writing the program and memtop (goes down when declaring arrays)
    getnotevalue returns the frequency of the MIDI note#

    Started to implement adr, that returns the address of a variable (= a pointer to it)


    Time to make a "BETA todo list..."

    Implement:

    - adr done
    - binary and hexadecimal notation done
    - chr$,val, str$, bin$,hex$,left$,right$,mid$ done
    - goto expr done
    - gosub/return/pop done
    - file operations done except print# and input#
    - on expr goto/gosub

    • input (in progress)

    Add a proper error reporting (now it is chaotic)
    Clean the code
    Bump the version# to 0.9


  • pik33pik33 Posts: 2,387
    edited 2023-08-28 21:22

    0.27

    Changelog from 0.25:

    Math function added: abs
    Added poke,dpoke,lpoke,peek,dpeek,lpeek,adr,fre,inkey$
    Added getnotevalue(), changed order of 'play' parameters
    'run' can now load and run the program if a filename provided
    If a filename is provided without ".bas" and the file doesn't exist. the interpreter will try to add ".bas" itself
    A loaded file name is kept by interpreter, then 'save' without parameters saves to that filename
    If no file was loades yet, the default name is 'noname.bas'
    'for-next' loop doesnt crash/work weird if a float parameters used: they are now rounded
    Symbolic note names can be used in format #c4 or #c#4. They are internally converted to frequencies in Hz, as single. This means you can 'print #a4' and got 440.0
    'dir' now lists the directory in 4-columns format
    Several more bugs fixed.

  • pik33pik33 Posts: 2,387
    edited 2023-08-29 13:49

    I started to enhance the screen editor. Now it is like in Atari 8-bit : the cursor can be moved everywhere, the line under the cursor can be corrected and Enter enters it. Editing is now much easier, no more rewriting the full line.

    This needs finishing - ins/del don't work yet, only bksp - and debugging, but the current version is now pushed to Github

    I also changed the resolution to 1024x600. That's because of these Waveshare touch screens. This messed with the aspect ratio. It seems a "graphics" instruction has to be added. 1024x576 for a monitor, 1024x600 for Waveshare 7", 800x480 for its 5" little brother... While changing 576<->600 is easy, going 800x480 can be more challenging in this version of the driver as it is based on 4-lines long rdfast. However 4*800 is 3200, it can be divided by 64, so this can be done without rewriting the driver.

  • pik33pik33 Posts: 2,387
    edited 2023-08-29 20:59

    I marked 0.28 as pre-beta

    It has now a full screen editing mode. Not an 'edit' as in PicoMite, but rather as in Atari 8bit, you can move the cursor with arrows and edit wherever you want, then enter the line with Enter. No more rewriting a full line to change one character.

    Also I added a string related functions: asc,chr$,len,mid$,left$,right$,str$,bin$,hex$,val

    A command/function list became long now:

    abs(x)                              if x is negative, multiply by -1, else left intact
    asc(string)                         returns ASCII code of the first character in the string
    acos(x)                             returns the inverse cosine 
    adr(var) (or addr or varptr)        returns the address of the variable (= a pointer) in the memory
    asin(x)                             returns the inverse sine
    atn(x)                              returns the inverse tangent
    beep frequency, time (b.)           generates the square vave at frequency in Hz for the time in ms
    bin$(value,length)                  returns a string that is a binary representation of the argument, in 'length' digits Length is optional
    box x1,y1,x2,y2                     draws a filled rectangle from x1,y1 to x2,y2
    brun filename  (br.)                loads and executes a binary file compiled for a P2 by anything
    chr$(value)                         returns a one-character string that represents a given ASCII code
    circle x,y,r (ci.)                  draws the empty circle with the center at x,y and radius r
    click on/off or 1/0                 switches the keyboard click on and off 
    cls                                 clears the screen
    color colornum  (c.)                sets a color for graphic operations. There are 256 colors, 16 hues (high nibble) and 16 brightnesses (low nibble) similar to the 8-bit Atari. 0 to 15 are greys
    cos(x)                              returns a cosine of x. The unit is now 1/360 of full circle (switching units is planned by deg and rad commands as in Atari Basic)
    csave (cs.)                         tries to save a program to an audio cassette. Experimental and there is no cload yet.
    cursor on/off or 1/0                switches the text cursor on and off. Because of a bug in this version, use 1/0 in programs. 
    defenv channel,params               defines the sound envelope for the channel
    defsnd channel, params              defines the waveform for the channel
    defsprite spritenum,x,y,w,h (ds.)   makes a sprite from a screen rectangle
    deg                                 switches trigonometric functions to 360 degree system
    dim                                 declares an array or a typed variable
    dir                                 lists the working directory of an SD card
    dpeek(x)                            returns a 16-bit unsigned value from the memory at address x
    dpoke x,val                         writes a 16-bit unsigned val to the memory at address x
    draw end_x, end_y (dr.)             draws the line to point end_x, end_y. This will be the starting point for the new draw. The first starting point can be set with 'plot'
    fcircle x,y,r (fc.)                 draws the filled circle with the center at x,y and radius r
    fill x,y,newcolor,oldcolor (fi.)    flood fill. Starts at x,y and replaces all pixels with oldcolor to newcolor until other color boundary fouund.
    font fontnum                        sets the font family for characters to print. 2 fonts are implemented, 0=Atari ST mono, 1=PC DOS
    for (f.)                            starts a loop (see program control)
    frame (fr.)                         draws an empty rectangle from x1,y1 to x2,y2
    fre                                 returns amount of free Basic memory
    getenvsustain(slot)                 gets the sustain point set by defenv, to use with setsustain
    getnotevalue(midinote)              returns the frequency of the MIDI note in Hz
    getpixel(x,y)                       returns the color of the pixel at screen position x,y. The function returns the bacgkround pixel color even if there is a sprite drawn over this pixel.
    goto line (g.)                      jumps to the line
    hex$(value)                         returns a string that is a hexadecimal representation of the argument, in 'length' digits Length is optimal, 8 used if not provided
    if                                  with 'then' and 'else' controls the program flow
    ink colornum (i.)                   sets the color of the characters to print
    inkey$                              returns one-character string of the last pressed key, or "" if no key pressed
    int                                 converts anything, including strings if doable, to integer
    left$(string,num)                   returns first num characters of the string
    len(string)                         returns the length of the string
    list startline, endline (l.)        outputs the code on the screen form startline to endline. If no endline specified, the program will be listed to the end. 
    load "filename" (lo.)               loads a Basic program from the file. May be used in format load filename - without ""
    lpeek(x)                            returns a 32-bit unsigned value from the memory at address x
    lpoke x,val                         writes a 32-bit unsigned val to the memory at address x
    mid$(string,pos,amount)             returns amount character of tthe string starting from pos. The base position is 1
    mode modenum (m.)                   sets "look and feel" of the interpreter. 0 - Atari style, 1 - PC amber, 2 - PC green, 3 - PC white, 4 - Atari ST mono 
                                        Names can be used instead of numbers: 'atari', pc_amber", 'pc_green', 'pc_white', 'st'
    mouse on/off or 1/0                 switches the mouse pointer on and off
    mousex                              returns the x coordinate of a mouse pointer
    mousey                              returns the y coordinate of a mouse pointer
    mousek                              returns the mouse key state: 0 - not pressed, 1-left, 2-right, 4-middle
    mousew                              returns the mousewheel position. It is unbounded 16-bit signed integer.
    new                                 clears the program memory and all variables
    next (n.)                           closes a 'for' loop
    paper colornum  (p.)                sets the background of the characters to print
    peek(x)                             returns an 8-bit unsigned value from the memory at address x
    pinfloat pin                        sets the pin to float
    pinhi pin                           sets the pin to logic 1 (normally about 3.3V)
    pinlo pin                           sets the pin to logic 0 (normally about 0V)
    pinread pin                         returns the pin logoc state (0 or 1)
    pinstart pin, mode, x,y             starts the smart pin mode and sets x,y registers of the pin     
    pintoggle pin                       toggles the state of the pin (from 0 to 1 or from 1 to 0). Doesn't work if the pin floats.
    pinwrite pin, value                 if value=0, sets the pin output to low, else sets the pin output to high. Use to blink a led.
    play channel, (parameters)          plays a sound
    plot x,y (pl.)                      sets a pixel color at x,y to the color determined by a previous "color" command and sets a new starting point for 'draw'
    poke x,val                          writes an 8-bit unsigned val to the memory at address x
    position x,y (po.)                  sets a cursor position. The x resolution is half a character, so multiply number of characters by 2. This allows centering strings that have odd number of characters.
    print (?)                           outputs to the screen and moves the cursor to the new line if , or ; is not used.
                                        Use , after an argument to print the new one after a tab (8 characters), use ; to print the next argument directly after the previous. 
    rad                                 switches trigonometric functions to radians
    rdpin pin                           returns the smartpin output register value, notifies the smart pin
    release channel                     makes the envelope in the audio channel to continue to the end. 
    right$(string,num)                  returns last num characters of the string
    rnd(value)                          returns a random value. If no arguments, it is a 32-bit unsigned integer. If integer or float parameter is given, it returns integer or float that is less than,0 the parameter.
    rqpin pin                           returns the smartpin output register value, does not notify the smart pin
    run                                 starts the program. You can use "run" inside the program to restart it.
    save filename (s.)                  saves the program to the file
    setdelay channel, delay             sets the delay in ms for the audio channel to wait after 'play' instruction. Default=0
    setenv channel,env#                 sets the predefined envelope for the audio channel. Redefine it with defenv if needed
    setlen channel, len                 sets the time of the sound in seconds. Default 1.0
    setpan channel, pan                 sets the stereo position, -1.0 left, +1.0 right, 0.0 center. Default 0.0
    setvol channel, vol                 sets the volume of the channel, from 0.0 to 16.384. Higher values will cause clipping; default=4.0
    setwave channel, wave#              sets the predefined waveform for the channel. Redefine it with defsnd.
    setsustain channel,point            sets the sustain point for the envelope. The envelope will stop there until 'release' command is executed
    sin(x)                              returns a sine of x. The unit is now 1/360 of full circle (switching units is planned by deg and rad commands as in Atari Basic)
    sprite spritenum,x,y (sp.)          move the sprite number sprite# (from 0 to 15
    sqr(x)                              returns the square root of x
    stick(joynum)                       returns the position of a digital joystick
    strig(joynum)                       returns the button state of a digital jystick
    str$(value)                         converts a value to a string. 
    tan(x)                              returns a tangent of x. The unit is now 1/360 of full circle (switching units is planned by deg and rad commands as in Atari Basic)
    val(string)                         convert a string to a number. If it can, it returns an integer, if not, returns a single. If failed, returns 0
    waitms time                         waits "time" miliseconds. Doesn't have any upper limits as it creates an internal loop when time>5000 ms
    waitclock (wc.)                     waits for the internal 5 ms/200Hz clock tick. The clock is vblank synchronized so there is 1 vblank for 4 ticks
    waitvbl (wv.)                       waits for the screen vertical blank. Use to synchronize the program with the screen refresh
    wrpin pin                           writes to the mode register of the smart pin
    wxpin pin                           writes to the X register of the smar tpin
    wypin pin                           writes to the Y register of the smart pin
    
  • @pik33 said:
    I started to enhance the screen editor. Now it is like in Atari 8-bit : the cursor can be moved everywhere, the line under the cursor can be corrected and Enter enters it. Editing is now much easier, no more rewriting the full line.

    This needs finishing - ins/del don't work yet, only bksp - and debugging, but the current version is now pushed to Github

    I also changed the resolution to 1024x600. That's because of these Waveshare touch screens. This messed with the aspect ratio. It seems a "graphics" instruction has to be added. 1024x576 for a monitor, 1024x600 for Waveshare 7", 800x480 for its 5" little brother... While changing 576<->600 is easy, going 800x480 can be more challenging in this version of the driver as it is based on 4-lines long rdfast. However 4*800 is 3200, it can be divided by 64, so this can be done without rewriting the driver.

    Wow, your Basic seems to be progressing nicely @pik33. Will have to give it a try soon.

    Coincidentally that Android Auto/CarPlay tablet thing I'm waiting on right now with the AHD camera input is also natively 1024x600, although it's a 9 inch screen not 7 inches like those Waveshare LCDs.

  • pik33pik33 Posts: 2,387
    edited 2023-08-30 18:37

    "Slow goto" seems to work. Now this is possible:

    10 a=5
    20 goto 10*a
    30 ?30
    40 ?40
    50 ?50
    

    The program prints "50"

    I called it "slow goto" as it has to find the jump target in the whole program and that can be very slow if the program is big. This can be slightly optimized in the future, to search not from the start, but from the current line, up and then down.

    If no target line found, no jump will be performed.

    Now, gosub/return
    Edit: gosub/return/pop done. The next step: input/read/data

  • @pik33 said:
    If no target line found, no jump will be performed.

    Or stop and output a "Line not found" error, which is perhaps safer.

  • jmgjmg Posts: 15,175

    @rogloh said:

    @pik33 said:
    If no target line found, no jump will be performed.

    Or stop and output a "Line not found" error, which is perhaps safer.

    The current design allows a useful CASE .. ELSE handling.

  • pik33pik33 Posts: 2,387
    edited 2023-08-31 09:16

    Case..else and other advanced things may go to v 2.0...

    I will leave this "not jump at all" as you can always add "end" to stop there or react to the invalid input as in the example below (I have no 'input' implement yet, but this is the next step)

    10 print "Input your age" : input a
    20 goto 100+10*int(a/120)
    30 print "You are an alien"  
    35 end
    100 ? "You are young" : goto 35
    110 ? "You are old" 
    
    

    Meanwhile I moved the memlo to $80000, and now poke and peek work in the continuous address space from 0 to $207FFFF, where the pointers <$80000 point to the HUB and >$2000000 point to the first 512k of the PSRAM. I put the audio sample buffers there, freeing 16k of hub from keeping these samples as the audio driver can play directly from the PSRAM. This also allows to make more than 8 definitions available. I also need the scratch space in the PSRAM, for example to make DIR display file names in alphabetic order instead of what it is now without wasting a precious hub ram space - not all things can go to the PSRAM, and the most memory consuming things are sprites. I don't have time in the video driver to put sprites in the PSRAM. However I can keep unused definitions of them there and download them on demand in vblank.

  • pik33pik33 Posts: 2,387
    edited 2023-08-31 17:30

    The interpreter became usable :)

    After testing the "audio nonsense" (name (c) Wuerfel21) I discovered it aliases as !@#$. Having a Paula based audio driver and aliases at the same time is, in reality, a full nonsense.
    I overused a 'skip' parameter in the driver that allows to finetune the frequency while introducing aliases and subharmonics.
    This means I need a better method to convert the frequency to the values passed to the driver's mailbox, and to do this, I needed to made several simple calculation. Instead of searching for a calculator ans a sheet of paper to write several values, or even much worse, run the spreadsheet and think how to program it (I am not fluent in using modern spreadsheets)... I simply wrote five lines in the interpeter and got my values listed on the screen :)

    Using the interpreter is also testing it and discovering what I forgot... this time it was log function that computes logarithm.
    I added it in the extended version: log(x) computes a natural logarithm, log(x,y) computes logarithm of x, that's base is y. The interpreter's structure allows to adding functions with variable number of parameters.. that's convenient.

    Now, to do, is to implement what I have computed using the interpreter, into the interpreter itself.

  • @pik33 said:
    After testing the "audio nonsense" (name (c) Wuerfel21) I discovered it aliases as !@#$.

    :wink:

  • pik33pik33 Posts: 2,387
    edited 2023-09-01 19:05

    There was a problem... I can either use 95 clocks per sample and noise dac, or 256 clocks per sample and pwm dac.

    If noise dac used, a Paula's philosophy can be used. Set a period, the sample rate is always integer*the wave frequency, then the aliases are harmonics.
    If PWM dac used, however, the base frequency is too low and the granularity of audio frequencies available to generate is too coarse.
    The funny stuff caused by the noise dac is hearable and very unpleasant with a sine wave of a low volume. The recording shows random peaks here and there, caused by the noise DAC itself.

    The workaround used:

    • the main driver loop works at Paula's frequency. I have to slightly go up with a system clock, to Paulax96.. (340500000)
    • when the samples are uploaded to the LUT buffer, there is a dropper that drops 5 samples from 8, passing only 3 of them to the buffer. The pattern is 10010010. That's why I had to go up from 95 to 96. 95 doesn't allow the dropper to be that simple. This introduces a jitter, but it works at MHz frequencies.
    • then the DAC works in PWM mode at 1.32 MHz

    This works. No ringing at low volumes, no inharmonic aliases.

    The sample rate is in range of about 8..17 kHz, slightly too low.. but higher SR doesn't provide a frequency granularity fine enough. I can keep the sample rate in one octave range as I still have the sample skip option, but it now can be a power of 2, so no subharmonics are introduced.

    The better solution is to make a filter instead of a dumb sample dropper. Maybe later. I still have to add on..goto/gosub, input, read and file ops to go beta.

  • pik33pik33 Posts: 2,387
    edited 2023-09-01 21:45

    While testing the audio, that's now good enough to left it alone until more important things added (=doesn't annoy with too much distortions), I add several more audio related instructions - changewave, changevol, changefreq, changepan, shutup
    Changexxx instructions changes the parameter while playing and without resetting the sample and envelope pointer. They also don't change saved defaults for the channel

    'Shutup' silences the audio. WIth a channel# it silences the channel, without any parameters silences all . That thing is very useful when audio experiments go wrong.

  • This discussion is making me think about porting my old P1 byte code basic interpreter to the P2. I just ordered an Edge module with 32MB of RAM. Is there a C library to access the RAM chip?

  • pik33pik33 Posts: 2,387
    edited 2023-09-02 15:45

    @"David Betz" said:
    This discussion is making me think about porting my old P1 byte code basic interpreter to the P2. I just ordered an Edge module with 32MB of RAM. Is there a C library to access the RAM chip?

    There is a rogloh's Spin2 driver. In my repository it is psram.spin2 (high level function set) and psram16drv.spin2 (low level stuff) or psram4.drv for 4-bit interface.

    Meanwhile, I added another instructions: rem, enter and round.

    rem is of course a comment. Enter loads the program, but does not do "new" before, so the new code can append that, what is already in the memory.

    'round' was added because 'int' in old school Basics truncates the float instead of rounding it, so now int does exactly that. As in most cases rounding a variable is more convenient, I had to add 'round' that rounds the variable.

  • pik33pik33 Posts: 2,387

    Open, close, get, put started to work. Not optimal in any way, it seems it will end with a class written in C, but now it's good it works at all. I have to find and correct a bug that doesn' allow to have a..f in hexadecimals.

  • pik33pik33 Posts: 2,387
    edited 2023-09-03 21:38

    A lot of cleaning and bug fixing. Dir now lists alphabetically sorted entries. Hexadecimals can have a..f in them. Abbreviations work after then and else.
    Constants can be predefined in format #name, so 'open' can be used in form open #3,#read,"filename". I have to copy/paste SPIN/PASM pin control constants there

    Cleaning the big mess that I did with the interpreter is at about 25%. This includes commenting, indentation, proper variable declaring and alphabetically sorting tokens and functions.
    I am doing this before implementing the last stuff planned for beta, as the mess became too big.

    These are tokens left as todo for a first beta:

    const token_input=181   'todo
    const token_read=182    'todo
    const token_data=183    'todo
    const token_cload=184   'todo
    const token_blit=185    'todo
    const token_playsample=186 'todo ps. channel,pointer,freq or #period ,vol,lstart,lend
    const token_coginit=192 'todo
    const token_on=193  'todo
    const token_delete=194  'todo
    const token_cd=195      'todo
    const token_copy=196    'todo
    const token_framebuf=197'todo
    
  • pik33pik33 Posts: 2,387
    edited 2023-09-04 20:30

    A funny bug found while cleaning the code. 'if" doesn't check for "then" - at all. It simply skips the token.... so this:

    10 if a=10 qqq b=2 : else b=3

    works as if 'qqq" was 'then'. Anything, even a keyword, does the job there. To be corrected...

    I am now about line 1800 of 5400 lines of the interpreter in the cleaning process

  • pik33pik33 Posts: 2,387

    0.31. Cleaned up : interpreter/tokenizer, precompiler and expression evaluator. To clean : runtime.

Sign In or Register to comment.