Welcome, Guest
You have to register before you can post on our site.

Username/Email:
  

Password
  





Search Forums

(Advanced Search)

Forum Statistics
» Members: 483
» Latest member: aplus
» Forum threads: 2,799
» Forum posts: 26,377

Full Statistics

Latest Threads
List of file sound extens...
Forum: Help Me!
Last Post: SMcNeill
20 minutes ago
» Replies: 13
» Views: 162
Merry Christmas Globes!
Forum: Programs
Last Post: Pete
2 hours ago
» Replies: 2
» Views: 21
Merry Christmas Globes!
Forum: Christmas Code
Last Post: SierraKen
3 hours ago
» Replies: 1
» Views: 16
fast file find with wildc...
Forum: Help Me!
Last Post: madscijr
4 hours ago
» Replies: 2
» Views: 45
Raspberry OS
Forum: Help Me!
Last Post: Pete
5 hours ago
» Replies: 1
» Views: 33
Tenary operator in QB64 w...
Forum: Utilities
Last Post: Pete
6 hours ago
» Replies: 6
» Views: 79
Video Renamer
Forum: Works in Progress
Last Post: Pete
6 hours ago
» Replies: 3
» Views: 54
Need help capturng unicod...
Forum: General Discussion
Last Post: SMcNeill
6 hours ago
» Replies: 24
» Views: 320
QB64PE v4.0 is now live!!
Forum: Announcements
Last Post: RhoSigma
7 hours ago
» Replies: 35
» Views: 1,044
Remark Remover (WIP)
Forum: Works in Progress
Last Post: Pete
7 hours ago
» Replies: 0
» Views: 12

 
  A Little Challenge: Spin the Circle
Posted by: NakedApe - 09-10-2024, 10:15 PM - Forum: Help Me! - Replies (24)

Can anyone make this program shorter and smoother? I played with it for a while and it's pretty good, but I'm wondering if there's a simpler, better approach to using the ASPECT value. (bplus, I'm looking at you.  Wink)

Code: (Select All)
Option _Explicit '                   A Spinning Circle
Screen _NewImage(600, 400, 32)
Dim As Integer b, c, counter '                  Playing with Aspects
Dim As Single aspect, adder
Dim As _Unsigned Long col
$Color:32
counter = 0: col = Red
Do
    aspect = 1: adder = .015 '                 initial values
    '                                                      ASPECTS 1 TO 70
    For c = 1 To 9
        For b = 1 To 10 '                           redraw circle 10 times adding to the aspect each loop
            Cls
            aspect = aspect + adder '          increase the aspect by adder
            Circle (_Width / 2, _Height / 2), 100, White, , , aspect
            Paint (_Width / 2, _Height / 2), col, White
            _Limit 110
            _Display
        Next b
        If aspect >= 70 Then Exit For '       @ ~90 degrees drop thru to reverse loops
        adder = adder * 2 '                        adder amounts have to double after each 10-loop cycle to look right-ish
    Next c
    '                                                       * now reverse the process *
    counter = counter + 1
    If counter Mod 2 <> 0 Then If col = Red Then col = Green Else col = Red '  flip colors on odd cycles

    For c = 1 To 9 '                                  ASPECTS 70 TO 1
        For b = 1 To 10
            Cls
            aspect = aspect - adder
            Circle (_Width / 2, _Height / 2), 100, White, , , aspect
            If aspect <= 1 Then Exit For
            Paint (_Width / 2, _Height / 2), col, White
            _Limit 110
            _Display
        Next b
        adder = adder / 2 '
    Next c

    counter = counter + 1
    If counter = 4 Then counter = 0
    If _KeyDown(27) Then System
Loop
System

Print this item

  Fake Sphere Mapping
Posted by: TerryRitchie - 09-10-2024, 07:42 PM - Forum: Programs - Replies (3)

Over in one of @bplus threads: https://qb64phoenix.com/forum/showthread.php?tid=272

I was intrigued by his sphere mapping routine. In that thread you can see the process I went through modifying the code attempting to make it faster. Here is what I believe to be the final modified version of bplus' code squeezing as much speed as I could out of it.

The routines use the QB64pe _MEM statements for outright speed. Pay particular attention to the rendering subroutine, RenderSphere. It uses the metacommands $CHECKING:OFF and $CHECKING:ON for an even greater boost in speed. If you are uncomfortable with these metacommands simply REM or remove them.

Documentation on how to use this little library is contained at the top of the code. A demo is also included in the code showing the simplicity of its use.

The .ZIP file below contains the world map image for the demo.

Update: The code below has been modified per NakedApe's discovery of an issue with Mac systems.

Code: (Select All)
'+----------------------------------------------------------------------------------------------------------------------------------+
'| Fake Sphere Mapping                                                                                                              |
'|        v2.0                                                                                                                      |
'|    Terry Ritchie                                                                                                                 |
'|                                                                                                                                  |
'| Adapted from code by bplus: https://qb64phoenix.com/forum/showthread.php?tid=272&pid=2647#pid2647                                |
'| Which was adapted from code by Paul Dunn: https://www.youtube.com/watch?v=0EGDJybA_HE                                            |
'| I contacted Paul Dunn and confirmed that the code in the video above is his original work.                                       |
'| Quote from Paul, "yep, this one is mine, worked out from an algorithm for mapping lat/long to a rectangle."                      |
'| Furthermore, the idea of using a longitude map came from here: http://fredericgoset.ovh/informatique/oldschool/en/spheremap.html |
'|                                                                                                                                  |
'| DOCUMENTATION:                                                                                                                   |
'|                                                                                                                                  |
'| STEP 1: Create a structure to hold a sphere.                                                                                     |
'| --------------------------------------------                                                                                     |
'|   DIM Mars AS D2SPHERE ' a sphere structure to contain Mars                                                                      |
'|                                                                                                                                  |
'|                                                                                                                                  |
'| STEP 2: Create the sphere from the structure to be used in later renderings.                                                     |
'| ----------------------------------------------------------------------------                                                     |
'|   MakeSphere Sphere, Radius, SphereImage                                                                                         |
'|                                                                                                                                  |
'|     Sphere      - a variable declared as TYPE D2SPHERE                                                                           |
'|     Radius      - the desired radius of the rendered output image                                                                |
'|                   Note: passing a value of zero for radius results in the sphere height equaling the height of the texture image |
'|     SphereImage - the texture image used to map the surface of the sphere                                                        |
'|                                                                                                                                  |
'|     Example: MakeSphere Mars, 0, MarsImage ' create a sphere with a height equaling the texture image                            |
'|                                                                                                                                  |
'|                                                                                                                                  |
'| STEP 3: Render the sphere output image.                                                                                          |
'| ---------------------------------------                                                                                          |
'|   RenderSphere Sphere, xOffset                                                                                                   |
'|                                                                                                                                  |
'|     Sphere - a variable declared as TYPE D2SPHERE and previously processed through the MakeSphere subroutine                     |
'|     xOffset - the x coordinate offset within the texture map image to start rendering                                            |
'|               Note: the RenderSphere subroutine will modify xOffset and return the result as needed                              |
'|                                                                                                                                  |
'|     Example: RenderSphere Mars, 0 ' render an output image of the sphere                                                         |
'|                                                                                                                                  |
'|                                                                                                                                  |
'| STEP 4: Utilize the rendered image.                                                                                              |
'| -----------------------------------                                                                                              |
'|   The rendered output image will be contained in the sub-variable .Sphere of the variable declared as TYPE D2SPHERE.             |
'|                                                                                                                                  |
'|     Example: _PUTIMAGE(0, 0), Mars.Sphere ' displayed the rendered sphere                                                        |
'|                                                                                                                                  |
'|                                                                                                                                  |
'| STEP 5: Clean up after yourself by removing all memory and image assets associated with the sphere when finished with it.        |
'| -------------------------------------------------------------------------------------------------------------------------        |
'|   FreeSphere Sphere                                                                                                              |
'|                                                                                                                                  |
'|     Sphere - a variable declared as TYPE D2SPHERE and previously processed through the MakeSphere subroutine                     |
'|                                                                                                                                  |
'|     Example: FreeSphere Mars ' the sphere is no longer needed                                                                    |
'|                                                                                                                                  |
'|     You can create as many sphere objects as memory allows, that's why it's important to remove unused spheres.                  |
'|                                                                                                                                  |
'+----------------------------------------------------------------------------------------------------------------------------------+

OPTION _EXPLICIT '             declare those variables son

TYPE D2SPHERE '                2D MAPPED SPHERE PROPERTIES
    Image AS LONG '            texture image to map onto sphere
    Sphere AS LONG '           rendered output image
    ImageWidth AS INTEGER '    width of image
    ImageHeight AS INTEGER '   height of image
    mImage AS _MEM '           memory contents of texture image
    mSphere AS _MEM '          memory contents of output image
    mMap AS _MEM '             memory contents of longitude map
END TYPE

' --------------------------
'| Begin demonstration code |
' --------------------------

DIM Earth AS D2SPHERE '        a sphere structure to display Earth
DIM EarthImage AS LONG '       Earth's texture map
DIM EarthOffset AS INTEGER '   x location of texture map to begin drawing

EarthImage = _LOADIMAGE("worldmap3.png", 32) '                       load texture map
MakeSphere Earth, 0, EarthImage '                                    create the Earth sphere structure
_FREEIMAGE EarthImage '                                              texture map no longer needed
SCREEN _NEWIMAGE(_WIDTH(Earth.Sphere), _HEIGHT(Earth.Sphere), 32) '  graphics screen same size as output image
EarthOffset = 0 '                                                    reset texture map x offset
DO '                                                                 begin demo loop
    RenderSphere Earth, EarthOffset '                                render the sphere image at x offset
    _PUTIMAGE (0, 0), Earth.Sphere '                                 display the output image
    EarthOffset = EarthOffset + 1 '                                  increment texture map x offset
    _DISPLAY '                                                       update screen with changes
LOOP UNTIL _KEYDOWN(27) '                                            leave when ESC key pressed
FreeSphere Earth '                                                   free all sphere assets
SYSTEM '                                                             return to the operating system

' ------------------------
'| End demonstration code |
' ------------------------


'------------------------------------------------------------------------------------------------------------------------------------------+
SUB FreeSphere (Sphere AS D2SPHERE) '                                                                                                      |
    '+-------------------------------------------------------------------------------------------------------------------------------------+
    '| Frees all memory and image assets associated with a sphere. Very important to use this to free assets before exiting program!       |
    '|                                                                                                                                     |
    '| Sphere - a user defined type variable as SPHERE                                                                                     |
    '+-------------------------------------------------------------------------------------------------------------------------------------+

    _MEMFREE Sphere.mMap '     free memory assets
    _MEMFREE Sphere.mSphere
    _MEMFREE Sphere.mImage
    _FREEIMAGE Sphere.Image '  free image assets
    _FREEIMAGE Sphere.Sphere

END SUB

'------------------------------------------------------------------------------------------------------------------------------------------+
SUB RenderSphere (Sphere AS D2SPHERE, xOffset AS INTEGER) '                                                                                |
    '+-------------------------------------------------------------------------------------------------------------------------------------+
    '| Renders a sphere's output image (.Sphere)                                                                                           |
    '|                                                                                                                                     |
    '| Sphere  - a user defined type variable as SPHERE                                                                                    |
    '| xOffset - x location within texture image to begin (note that this value can be changed by the subroutine and passed back)          |
    '+-------------------------------------------------------------------------------------------------------------------------------------+

    DIM x AS INTEGER '            horizontal counter
    DIM y AS INTEGER '            vertical counter
    DIM Mapx AS INTEGER '         longitude map x coordinate
    DIM Pixel AS _UNSIGNED LONG ' image pixel
    DIM MapOffset AS _OFFSET '    memory location within longitude map
    DIM SphereOffset AS _OFFSET ' memory location within output image
    DIM ImageOffset AS _OFFSET '  memory location within texture image

    $CHECKING:OFF
    IF xOffset > Sphere.ImageWidth - 1 THEN xOffset = 0 '                          reset x offset if needed
    y = 0 '                                                                        reset vertical counter
    DO '                                                                           begin vertical loop
        MapOffset = Sphere.mMap.OFFSET + (y * Sphere.ImageHeight * 2) '            start of horizontal line within longitude map
        SphereOffset = Sphere.mSphere.OFFSET + (y * Sphere.ImageHeight * 4) '      start of horizontal line within output image
        ImageOffset = Sphere.mImage.OFFSET + (y * Sphere.ImageWidth * 8) '         start of horizontal line within texture image
        x = 0 '                                                                    reset horizontal counter
        DO '                                                                       begin horizontal loop
            _MEMGET Sphere.mMap, MapOffset + (x * 2), Mapx '                       get x texture coordinate
            IF Mapx <> -1 THEN '                                                   valid coordinate?
                _MEMGET Sphere.mImage, ImageOffset + (Mapx + xOffset) * 4, Pixel ' yes, get pixel from image
                _MEMPUT Sphere.mSphere, SphereOffset + (x * 4), Pixel '            apply pixel to output image
            END IF
            x = x + 1 '                                                            increment horizontal counter
        LOOP UNTIL x = Sphere.ImageHeight '                                        leave when entire horizontal line processed
        y = y + 1 '                                                                increment vertical counter
    LOOP UNTIL y = Sphere.ImageHeight '                                            leave when entire vertical line processed
    $CHECKING:ON

END SUB

'------------------------------------------------------------------------------------------------------------------------------------------+
SUB MakeSphere (Sphere AS D2SPHERE, UserRadius AS INTEGER, Image AS LONG) '                                                                |
    '+-------------------------------------------------------------------------------------------------------------------------------------+
    '| Create a sphere structure to be used later when rendering the sphere.                                                               |
    '|                                                                                                                                     |
    '| Sphere     - a user defined type variable as SPHERE                                                                                 |
    '| UserRadius - the desired sphere radius (supply a value of zero to use the radius of the image)                                      |
    '| BaseImage  - the image to be mapped onto the sphere                                                                                 |
    '|                                                                                                                                     |
    '| Example: MakeSphere Earth, 0, WorldMap ' define sphere using radius of image                                                        |
    '|                                                                                                                                     |
    '| Note: NakedApe on the QB64pe forum noted a change was needed in the code below.                                                     |
    '|       BaseImage = _COPYIMAGE(Image) needed to be changed to _COPYIMAGE(Image, 32)                                                   |
    '|       Without this change the code would not run on a Mac. Thanks to NakedApe for pointing this out.                                |
    '+-------------------------------------------------------------------------------------------------------------------------------------+

    CONST HALFPI = 1.570796326794897 ' half of Pi
    CONST rPI = .318309891613572 '     Pi reciprocated
    DIM TempImage AS LONG '            temporary resizing image if modifying radius
    DIM BaseImage AS LONG '            final image to map to sphere
    DIM Radius AS SINGLE '             sphere radius
    DIM Index AS _UNSIGNED LONG '      array memory offset for each value
    DIM sLongitude AS SINGLE '         sine longitude calculation
    DIM Longitude AS SINGLE '          longitude calculation
    DIM x AS INTEGER '                 horizontal counter
    DIM y AS INTEGER '                 vertical counter

    IF UserRadius <> 0 THEN '                                                          use the radius of the base image?

        ' ------------------------------------------------------------
        '| Resize base image to fit passed in radius supplied by user |
        ' ------------------------------------------------------------

        TempImage = _NEWIMAGE((_WIDTH(Image) * UserRadius * 2) / _HEIGHT(Image), UserRadius * 2, 32) ' no, create resized temp image
        _PUTIMAGE (0, 0)-(_WIDTH(TempImage) - 1, _HEIGHT(TempImage) - 1), Image, TempImage '           resize base image into temp image
        BaseImage = _COPYIMAGE(TempImage) '                                                            copy temp image to base image
        _FREEIMAGE TempImage '                                                                         remove temp image
    ELSE '                                                                             yes
        BaseImage = _COPYIMAGE(Image, 32) '                                            copy image to base image
    END IF

    ' --------------------------------
    '| Create image and memory assets |
    ' --------------------------------

    Sphere.ImageWidth = _WIDTH(BaseImage) '                                            get width of base image
    Sphere.ImageHeight = _HEIGHT(BaseImage) '                                          get height of base image
    Sphere.Image = _NEWIMAGE(Sphere.ImageWidth * 2, Sphere.ImageHeight * 2, 32) '      create texture image
    _PUTIMAGE (0, 0), BaseImage, Sphere.Image '                                        draw base image left justified on texture image
    _PUTIMAGE (Sphere.ImageWidth, 0), BaseImage, Sphere.Image '                        draw base image right justified on texture image
    Sphere.mImage = _MEMIMAGE(Sphere.Image) '                                          get memory contents of texture image
    Sphere.Sphere = _NEWIMAGE(Sphere.ImageHeight, Sphere.ImageHeight, 32) '            create output image
    Sphere.mSphere = _MEMIMAGE(Sphere.Sphere) '                                        get memory contents of output image
    Sphere.mMap = _MEMNEW(Sphere.ImageHeight * Sphere.ImageHeight * 2) '               create longitude array in memory

    ' -------------------------------------------------------------------
    '| Create a longitude map of sphere                                  |
    '| The idea of using a translation array comes from this site:       |
    '| http://fredericgoset.ovh/informatique/oldschool/en/spheremap.html |
    ' -------------------------------------------------------------------

    Radius = Sphere.ImageHeight * .5 '                                                 calculate sphere radius
    y = 0 '                                                                            reset vertical counter
    DO '                                                                               begin vetical loop
        x = 0 '                                                                        reset horizontal counter
        DO '                                                                           begin horizontal loop
            Index = (y * Sphere.ImageHeight + x) * 2 '                                 memory location within nMap

            ' -----------------------------------------------------------------
            '| (x - radius)                              = centered x position |
            '| (y - radius)                              = centered y position |
            '| (y - radius) / radius                     = sine latitude       |
            '| _ASIN((y - radius) / radius)              = latitude            |
            '| radius * COS(_ASIN((y - radius) / radius) = sphere radius       |
            ' -----------------------------------------------------------------

            sLongitude = (x - Radius) / (Radius * COS(_ASIN((y - Radius) / Radius))) ' calculate sine longitude of pixel
            IF ABS(sLongitude) <= 1 THEN '                                             is pixel inside the circle?
                Longitude = _ASIN(sLongitude) + HALFPI '                               yes, complete longitude calculation
                _MEMPUT Sphere.mMap, Sphere.mMap.OFFSET + Index, (Longitude * Sphere.ImageWidth * .5) * rPI AS INTEGER ' store image x coor
            ELSE '                                                                     no, pixel is outside of circle
                _MEMPUT Sphere.mMap, Sphere.mMap.OFFSET + Index, -1 AS INTEGER '       mark x coordinate as outside of circle
            END IF
            x = x + 1 '                                                                increment horizontal counter
        LOOP UNTIL x = Sphere.ImageHeight '                                            leave when entire horizontal line processed
        y = y + 1 '                                                                    increment vertical counter
    LOOP UNTIL y = Sphere.ImageHeight '                                                leave when entire vertical line processed

END SUB



Attached Files Thumbnail(s)
   

.zip   Worldmap3.zip (Size: 3.1 MB / Downloads: 26)
Print this item

  OpenAI's ChatGPT in QB64
Posted by: SpriggsySpriggs - 09-10-2024, 06:46 PM - Forum: General Discussion - Replies (2)

Like Google's Gemini and Perplexity's AI, we can also interact with ChatGPT.

Quote:Tell me about the Tesla Model 3
   

Print this item

  InputBox
Posted by: Petr - 09-10-2024, 12:14 PM - Forum: Petr - Replies (7)

I wrote my own version of inputbox. Its limitation is that it is only intended for a resolution of 1920x1080 (my default), so it was satisfactory for the program for which it was intended.

It supports marking and deleting part of the text, the clipboard and scrolling on the monitor if the dialog is caught by the mouse by the upper edge. Maybe it could be of interest to someone.

Code: (Select All)


Screen _NewImage(1920, 1080, 32)
Cls 'need for black with alpha 255 in background (or can be used image)
_FullScreen


D$ = "programmer"
N = Val(InputBoxZ("Window title", "This program now tests:", D$, 1, 0))
_Display
Print N, D$ 'N = buttons status, D$ = text inserted in box
_Display
End



Function InputBoxZ$ (Tit As String, Message As String, Default As String, DefaultVal, BoxType)
    'designated for 1920 x 1080 resolution only!

    'ESC = -1; OK = 1; CANCEL = 0

    B.Height = 125
    B.Width = 351
    B.X = B.Width \ 2 - _Width \ 2
    If B.X < 0 Then
        B.X = _Width \ 2 - B.Width \ 2
    End If
    B.Y = B.Height \ 2 - _Height \ 2
    If B.Y < 0 Then
        B.Y = _Height \ 2 - B.Height \ 2
    End If

    'It saves the background in ram during the dialog, nothing
    'else happens until it is confirmed or finished, it is not a pass-through function
    Backgr& = _CopyImage(0, 32) '
    GPos = _PrintWidth(Default)
    t$ = Default$

    Do Until Done
        _PutImage , Backgr&, _Dest
        K& = _KeyHit
        Select Case K&
            Case 27: InputBoxZ$ = "-1": Exit Function 'After Esc return -1
            Case 13: InputBoxZ$ = Str$(DefaultVal): Exit Function 'After Enter is returned defaultval (is changed by user)
                'OK = 1, Cancel = 0,
        End Select

        While _MouseInput
        Wend
        MX = _MouseX
        MY = _MouseY
        LB = _MouseButton(1)

        'solution for moving dialog on the screen by mouse
        If PLock Then GoTo Shift 'GoTo enables scrolling for as long as the button is pressed, even if you escape from the dialog's coordinates
        If MX >= B.X And MX <= B.Width + B.X Then
            If MY >= B.Y And MY <= B.Y + 24 Then
                Shift:
                If LB = -1 Then
                    PLock = 1
                    If DoX = 0 Then
                        DoX = MX - B.X
                        DoY = MY - B.Y
                    End If
                    B.X = MX - DoX
                    B.Y = MY - DoY
                Else
                    DoX = 0
                    PLock = 0
                End If
            End If
        End If


        Line (B.X, B.Y)-(B.Width + B.X, B.Height + B.Y), _RGB32(240), BF 'whole box area
        Line (B.X, B.Y)-(B.Width + B.X, B.Y + 24), _RGB32(255), BF '      title area

        _PrintMode _KeepBackground
        Color _RGB32(188, 153, 171)
        _PrintString (B.X + 5, B.Y + 5), Tit$
        Color _RGB32(0)
        _PrintString (B.X + 9, B.Y + 34), Message$

        BoxZ B.X + 12, B.Y + 57, B.X + B.Width - 12, B.Y + 77 'draw box for inserting text

        'axis X
        ButtonWdth = 78
        ButtonRightOkraj = 13
        ButtonMezi = 13

        'axis Y
        ButtonHght = 20
        ButtonSpodniOkraj = 15

        LHx = B.X + B.Width - ButtonWdth - ButtonRightOkraj '  left upper X Cancel button
        PHx = LHx + ButtonWdth '                              right upper X Cancel button
        LDy = B.Y + B.Height - ButtonSpodniOkraj - ButtonHght 'left bottom Y Cancel button
        Lhy = LDy + ButtonHght '                              left upper Y Cancel button

        PHx1 = PHx - ButtonMezi - ButtonWdth
        LHx1 = PHx1 - ButtonWdth

        ButtonActive$ = ""

        Select Case BoxType
            Case 0
                'defaultVal set, which button is after run set as default
                Buttons = 2
                B1$ = "OK"
                B2$ = "Cancel"
                'Right button: Cancel
                BoxButtonZ LHx, LDy, PHx, Lhy '  cancel
                BoxButtonZ LHx1, LDy, PHx1, Lhy 'OK

                CPW = _PrintWidth(B2$)
                OPW = _PrintWidth(B1$)


                T1 = LHx + (PHx - LHx) \ 2 - CPW \ 2
                T2 = LHx1 + (PHx1 - LHx1) \ 2 - OPW \ 2
                TY = Lhy + (LDy - Lhy) \ 2 - _FontHeight \ 2 + 2




                'ocad poanglictovat dolu


                '    If DefaultVal = 0 Then Color _RGB32(0) Else Color _RGB32(188, 153, 171)    'original ma oba popisky cerne,
                _PrintString (T1, TY), B2$ '                                                      pri kliknuti na volbu zustane text cerny,
                '  If DefaultVal = 1 Then Color _RGB32(0) Else Color _RGB32(188, 153, 171)    '  oramovani se ale zmeni z BoxButtonZ na BoxZ
                _PrintString (T2, TY), B1$ '                                                      a okolo textu se udela jeste binarni Line B

                If LB = -1 And MX > LHx1 And MX < PHx1 And MY > LDy And MY < Lhy Then DefaultVal = 1: ButtonActive$ = "OK"
                If LB = -1 And MX > LHx And MX < PHx And MY > LDy And MY < Lhy Then DefaultVal = 0: ButtonActive$ = "Cancel"
                If MX > B.X + 12 And MX < B.X + B.Width - 12 And MY > B.Y + 57 And MY < B.Y + 77 Then _MouseShow "Text" Else _MouseShow "default"

                If LB = -1 And MX > B.X + 12 And MX < B.X + B.Width - 12 And MY > B.Y + 57 And MY < B.Y + 77 Or DialogAct = 1 Then
                    DialogAct = 1
                    'logika vkladani textu do textoveho pole

                    ' If LB = -1 And MX > B.X + 12 And MX < B.X + B.Width - 12 And MY > B.Y And MY < B.Height Then

                    If Dialog& = 0 Then
                        Dialog& = _NewImage(B.Width, B.Height, 32)
                        _PutImage (B.X, B.Y)-(B.Width + B.X, B.Height + B.Y), 0, Dialog&
                    End If


                    Do Until K$ = Chr$(13) Or ButtonActive$ <> ""
                        K$ = InKey$


                        'urcit grafickou polohu kurzoru pri kliknuti do textu - uz  ok
                        If MX > B.X + 12 And MX < B.X + B.Width - 12 And MY > B.Y + 57 And MY < B.Y + 77 Then
                            If LB = -1 Then

                                If ShiftStart > 0 And Len(K$) = 0 Then
                                    ShiftStart = 0
                                    ShiftEnd = 0
                                    ShiftLock = 0
                                    _Continue
                                End If

                                If MX - (B.X + 12) < _PrintWidth(t$) + 12 And MX > B.X + 12 Then
                                    UPGI = _FontWidth * ((MX - (B.X + 12)) \ _FontWidth)
                                    GPos = UPGI - _FontWidth
                                End If
                                
                                If GPos < 0 Then GPos = 0

                                If MemG = 0 Then MemG = GPos + _FontWidth

                            End If

                            'support for select text with mouse

                            If LB = -1 And MemG <> GPos + _FontWidth Then
                                ShiftStart = MemG
                                ShiftEnd = GPos + _FontWidth
                                GoTo ppp
                            End If

                            If LB = 0 And MemG > 0 Then
                                MemG = 0
                            End If
                        End If 'end condition for locking window when is moved on the screen with mouse


                        'Shift press support for text select
                        ShiftLeft& = _KeyDown(100303)
                        ShiftRight& = _KeyDown(100304)

                        If ShiftLeft& Or ShiftRight& Then
                            If Len(K$) = 1 Then ShiftLock = 0: GoTo DoNotShift
                            If ShiftStart = 0 Then ShiftStart = GPos + _FontWidth
                            If ShiftStart > 0 Then ShiftEnd = GPos + _FontWidth

                            ppp: 'whin selecting text with mouse, use block for selecting with keyboard by there

                            ShiftLock = 1
                            ITLS = ShiftStart \ _FontWidth
                            ITLR = ShiftEnd \ _FontWidth - ShiftStart \ _FontWidth
                            If ITLR < 0 Then
                                ITLR = ShiftStart \ _FontWidth - ShiftEnd \ _FontWidth
                                ITLS = ShiftEnd \ _FontWidth
                            End If
                            InsertedText$ = Mid$(t$, ITLS, ITLR)
                        Else
                            ShiftLock = ShiftStart 'Delete / Shift logic blocking
                        End If

                        'Clipboard support

                        'ShifStart is reseted after sopmething is pressed on the keyboard
                        If K$ = Chr$(3) Then _Clipboard$ = InsertedText$ 'insert to clipboard

                        If ShiftLeft& = 0 And ShiftRight& = 0 And K$ <> "" Then
                            If Len(InsertedText$) And Len(K$) = 1 Then
                                If Asc(K$) > 31 And Asc(K$) < 127 Then 'limit for text characters

                                    ' If part of the text is marked and you press a letter,
                                    'Delete the marked part and write from its original left side

                                    If ShiftStart > ShiftEnd Then Swap ShiftStart, ShiftEnd
                                    kk$ = ""
                                    tA$ = Left$(t$, ShiftStart \ _FontWidth - 1)
                                    tB$ = Right$(t$, Len(t$) - ShiftEnd \ _FontWidth + 1)
                                    If Asc(K$) > 31 And Asc(K$) < 127 Then kk$ = K$
                                    t$ = tA$ + kk$ + tB$
                                    GPos = ShiftStart
                                    'Print "Ta a Tb:"; tA$, tB$, ShiftStart, ShiftEnd: _Display
                                    tA$ = ""
                                    tB$ = ""
                                    ShiftStart = 0
                                    InsertedText$ = ""
                                    _Continue
                                End If
                            End If

                            DoNotShift:
                            tA$ = ""
                            tB$ = ""
                            ShiftStart = 0
                            InsertedText$ = ""
                            'Sound 299, .1 'every character can do sound Smile
                        End If

                        'last upgrade: 2024-24-02
                        If K$ = Chr$(0) + Chr$(75) Then
                            If GPos > 0 Then GPos = GPos - _FontWidth 'arrow left
                        End If

                        If K$ = Chr$(0) + Chr$(77) Then
                            If GPos < _PrintWidth(t$) Then GPos = GPos + _FontWidth 'arrow right
                        End If


                        If K$ = Chr$(22) Then 'clipboard inserting is supported (Ctrl+V)
                            t$ = Left$(_Clipboard$, 30)
                            GPos = _FontWidth * Len(t$)
                        End If

                        If LB = -1 Then AllowText = 0 Else AllowText = 1 'when textbox is moved on the screen, text inserting is blocked
                        If AllowText = 1 Then
                            If Len(t$) < 30 And Len(K$) Then
                                If Asc(K$) > 31 And Asc(K$) < 177 Then
                                    TextPos = GPos \ _FontWidth
                                    TextA$ = Mid$(t$, 1, TextPos)
                                    TextB$ = Mid$(t$, TextPos + 1, Len(t$) - TextPos)
                                    t$ = TextA$ + K$ + TextB$
                                    GPos = GPos + _FontWidth
                                    K$ = ""
                                End If
                            End If
                        Else
                            K$ = ""
                        End If


                        If K$ = Chr$(8) Then 'Backspace support
                            If ShiftLock Then GoTo ShiftedLock
                            If Len(t$) > 0 Then
                                T1$ = Mid$(t$, 1, (GPos - 1) \ _FontWidth) 'the left part of the string according to GPos shortened by one character
                                T2$ = Right$(t$, Len(t$) - Len(T1$) - 1) 'right part of the string
                                If GPos <= 0 Then _Continue 'if GPos (cursor position) is 0

                                t$ = T1$ + T2$
                                Default$ = t$
                                GPos = GPos - _FontWidth
                                Color _RGB32(255)
                                _PrintMode _FillBackground
                                _PrintString (B.X + 24 + GPos, B.Y + 60), Chr$(255)
                                _PrintMode _KeepBackground
                                Rem ----------------------------------
                            End If
                            'if piece of the text is inserted, delete it

                            ShiftedLock:
                            Kpocet = ITLR
                            Kstart = ITLS
                            If ShiftLock Then
                                LeftT$ = Mid$(t$, 1, Kstart - 1)
                                RightT$ = Mid$(t$, Kstart + Kpocet)
                                t$ = LeftT$ + RightT$
                                ShiftLock = 0
                                GPos = _PrintWidth(t$)
                            End If

                        End If

                        If K$ = Chr$(0) + Chr$(83) Then 'delete support
                            If ShiftLock Then GoTo ShiftedLockB
                            If Len(t$) > 0 Then
                                T1d$ = Left$(t$, GPos \ _FontWidth) 'left part of the  string by GPos minus one character
                                T2d$ = Right$(t$, Len(t$) - Len(T1d$) - 1) 'right part of the string
                                t$ = T1d$ + T2d$
                                Default$ = t$

                                Color _RGB32(255)
                                _PrintMode _FillBackground
                                _PrintString (B.X + 24 + GPos, B.Y + 60), Chr$(255)
                                _PrintMode _KeepBackground
                                Rem LINE----------------------------------
                            End If

                            ShiftedLockB:
                            Kpocet = ITLR
                            Kstart = ITLS
                            If ShiftLock Then

                                LeftT$ = Mid$(t$, 1, Kstart - 1)
                                RightT$ = Mid$(t$, Kstart + Kpocet)
                                t$ = LeftT$ + RightT$
                                Default$ = t$
                                GPos = _PrintWidth(t$)
                                ShiftLock = 0
                            End If
                        End If


                        If K$ = Chr$(0) + Chr$(71) Then GPos = 0 'Home key
                        If K$ = Chr$(0) + Chr$(79) Then GPos = _PrintWidth(t$) 'Home key

                        _PrintMode _FillBackground

                        Line (B.X + 12, B.Y + 57)-(B.X + B.Width - 12, B.Y + 77), _RGB32(255), BF 'clear background
                        _PrintString (B.X + 24, B.Y + 60), t$

                        'if part of the text is selected, colorize it
                        If ShiftStart Then
                            Line (B.X + 16 + ShiftStart, B.Y + 57)-(B.X + 16 + ShiftEnd, B.Y + 77), _RGBA32(0, 0, 127, 117), BF
                        End If


                        If Timer * 10 Mod 10 < 5 Then 'cursor blicking
                            Line (B.X + 24 + GPos, B.Y + 60)-(B.X + 24 + GPos, B.Y + 72), _RGB32(255)
                        Else
                            Line (B.X + 24 + GPos, B.Y + 60)-(B.X + 24 + GPos, B.Y + 72), _RGB32(0)
                        End If
                        Color _RGB32(0), _RGB32(255)

                        While _MouseInput
                        Wend
                        MX = _MouseX
                        MY = _MouseY
                        LB = _MouseButton(1)

                        If LB = -1 And MX > LHx1 And MX < PHx1 And MY > LDy And MY < Lhy Then
                            DefaultVal = 1
                            ButtonActive$ = "OK"
                            Default$ = t$
                        End If
                        If LB = -1 And MX > LHx And MX < PHx And MY > LDy And MY < Lhy Then
                            DefaultVal = 0
                            ButtonActive$ = "Cancel"
                        End If
                        If MX > B.X + 12 And MX < B.X + B.Width - 12 And MY > B.Y + 57 And MY < B.Y + 77 Then
                            _MouseShow "Text"
                        Else
                            _MouseShow "default"
                            Exit Do
                        End If
                        _Display
                    Loop
                Else
                    DialogAct = 0
                End If
                Default$ = t$
        End Select

        _PrintMode _KeepBackground
        _PrintString (B.X + 24, B.Y + 60), t$

        If Len(ButtonActive$) Then
            Do Until LB = 0
                While _MouseInput: Wend
                LB = _MouseButton(1)
                Select Case ButtonActive$
                    Case "OK"
                        BoxZ LHx1, LDy, PHx1, Lhy 'for OK
                        Line (LHx1, LDy)-(PHx1, Lhy), _RGB32(240), BF
                        Color _RGB32(0)
                        _PrintString (T2, TY), B1$
                        InputBoxZ$ = "1"

                    Case "Cancel"
                        BoxZ LHx, LDy, PHx, Lhy '  for cancel
                        Line (LHx, LDy)-(PHx, Lhy), _RGB32(240), BF
                        Color _RGB32(0)
                        _PrintString (T1, TY), B2$
                        InputBoxZ$ = "0"
                End Select
                _Display
                _Limit 100
            Loop
            Done = 1
            LB = 0
        End If
        _Display
        _Limit 120
        Color _RGB32(255)
        If K$ = Chr$(13) Then Exit Do
    Loop

    _PutImage , Backgr&, _Dest
    _FreeImage Backgr&
    Color _RGB32(255), _RGB32(0)
    _PrintMode _FillBackground
    Default$ = t$
End Function

Sub BoxZ (Xs, Ys, Xe, Ye) 'imitation of the appearance of buttons for concrete resolution according to windows buttons

    Line (Xs, Ys)-(Xe, Ye), _RGB32(255), BF
    'bootm lines:
    Line (Xs - 1, Ye + 1)-(Xe + 1, Ye + 1), _RGB32(227)
    Line (Xs - 1, Ye + 2)-(Xe + 1, Ye + 2), _RGB32(255)

    'right lines
    Line (Xe + 1, Ys - 1)-(Xe + 1, Ye + 1), _RGB32(227)
    Line (Xe + 2, Ys - 1)-(Xe + 2, Ye + 1), _RGB32(255)

    'upper two lines
    Line (Xs - 2, Ys - 2)-(Xe + 1, Ys - 2), _RGB32(105)
    Line (Xs - 1, Ys - 1)-(Xe + 1, Ys - 1), _RGB32(160)

    'left two lines
    Line (Xs - 2, Ys - 2)-(Xs - 2, Ye + 2), _RGB32(105)
    Line (Xs - 1, Ys - 1)-(Xs - 1, Ye + 1), _RGB32(160)

End Sub

Sub BoxButtonZ (Xs, Ys, Xe, Ye) 'test - ok
    Rem  compared to BoxZ what's on the right will be on the left, what's up will be down
    'One button description BoxButtonZ or ButtonZ is applied to the button in the unclicked state
    'and the other description is applied to the button when it is pressed

    Line (Xs, Ys)-(Xe, Ye), _RGB32(240), BF
    'bottom lines
    Line (Xs - 1, Ye + 1)-(Xe + 1, Ye + 1), _RGB32(160)
    Line (Xs - 1, Ye + 2)-(Xe + 1, Ye + 2), _RGB32(105)

    'right lines
    Line (Xe + 1, Ys - 1)-(Xe + 1, Ye + 1), _RGB32(160) 'tyto 2 prohozeny barvy
    Line (Xe + 2, Ys - 1)-(Xe + 2, Ye + 1), _RGB32(105)

    'upper lines
    Line (Xs - 2, Ys - 2)-(Xe + 1, Ys - 2), _RGB32(255)
    Line (Xs - 1, Ys - 1)-(Xe + 1, Ys - 1), _RGB32(227)

    'left lines
    Line (Xs - 2, Ys - 2)-(Xs - 2, Ye + 2), _RGB32(255)
    Line (Xs - 1, Ys - 1)-(Xs - 1, Ye + 1), _RGB32(227)
End Sub

Print this item

  Exploring QB64-PE default soundfont patches
Posted by: Dav - 09-10-2024, 02:59 AM - Forum: Programs - Replies (56)

I was curious as to what all the default MIDI soundfont patches sounded like, and I also wanted to put together a way of grabbing those sounds somehow in code to use, so this function is the result.  It just grabs 1 midi note.  I don't think I'm calculating the ticks and duration right, but at least I can hear the sound patches available.  There's some real neat ones.  I'm probably not making a valid MIDI data file here, but at least it loads/plays.

- Dav

NOTE:  Get the lastest version, now called MidiNotes, HERE

Code: (Select All)
'Exploring QB64-PE default soundfont patches.
'Makes MIDI a note and play's it from memory.
'Dav, SEP/2024

'Cycles throuh all default sound patchs 127-0

$Unstable:Midi
$MidiSoundFont: Default

'cycle through all sounds, press any key to quit.

For patch = 127 To 0 Step -1
    Print "Patch#"; patch
    note$ = MidiNote$(60, patch, 60, 1)
    midisound& = _SndOpen(note$, "memory")
    _SndPlay midisound&
    _Delay 1
    _SndStop midisound&
    _SndClose midisound&
    If InKey$ <> "" Then End
Next

Function MidiNote$ (tempo&, patch, note, duration&)

    TicksPerQuarterNote = 96

    'Make MIDI Header Chunk (MThd)
    MThd$ = Chr$(77) + Chr$(84) + Chr$(104) + Chr$(100) ' "MThd"
    'Make Header size
    MThd$ = MThd$ + Chr$(0) + Chr$(0) + Chr$(0) + Chr$(6)
    'Make format type (1 = single track)
    MThd$ = MThd$ + Chr$(0) + Chr$(1)
    'Make number of tracks (1)
    MThd$ = MThd$ + Chr$(0) + Chr$(1)
    'Make division = 96 (ticks per quarter note)
    MThd$ = MThd$ + Chr$(0) + Chr$(96)

    'calculate microseconds per beat from tempo& in BPM
    MicroSecsPerBeat& = 60000000 \ tempo& '(converts BPM to microseconds per beat)

    'Get msb/mb/lsb from MicroSecsPerBeat& for saving tempo
    '(midi requires 3 bytes for this info)
    msb = (MicroSecsPerBeat& \ 65536) And 255 'most Significant Byte
    middle = (MicroSecsPerBeat& \ 256) And 255 'middle Byte
    lsb = MicroSecsPerBeat& And 255 'least Significant Byte

    'Make the tempo data + the 3 bytes
    TrackData$ = TrackData$ + Chr$(0) + Chr$(255) + Chr$(81) + Chr$(3) + Chr$(msb) + Chr$(middle) + Chr$(lsb)

    'Set Program number (patch) to use
    TrackData$ = TrackData$ + Chr$(0) + Chr$(192) + Chr$(patch)

    'Set Note On: play note value (with velocity 127)
    TrackData$ = TrackData$ + Chr$(0) + Chr$(144) + Chr$(note) + Chr$(127)

    'convert duration& in beats to ticks& (how long to play the note)
    ticks& = duration& * TicksPerQuarterNote

    'Set Note Off: Stop playing note after specified duration& in ticks&
    TrackData$ = TrackData$ + Chr$(ticks&) + Chr$(128) + Chr$(note) + Chr$(64)

    'Make track end event
    TrackData$ = TrackData$ + Chr$(0) + Chr$(255) + Chr$(47) + Chr$(0)

    'Make the MTrk header
    MTrk$ = Chr$(77) + Chr$(84) + Chr$(114) + Chr$(107) ' MTrk

    'Make the track data length (4 bytes)
    TrackLen& = Len(TrackData$)
    TrackLength$ = Chr$((TrackLen& \ 16777216) And 255) + Chr$((TrackLen& \ 65536) And 255) + Chr$((TrackLen& \ 256) And 255) + Chr$(TrackLen& And 255)

    'Put it all together
    MidiNote$ = MThd$ + MTrk$ + TrackLength$ + TrackData$

End Function

Print this item

  open multiple screens at once
Posted by: drewdavis - 09-09-2024, 04:34 AM - Forum: Help Me! - Replies (2)

Anyone else experiment with different ways to have multiple screens open at a time using QB64?  I've experimented with using The clipboard to send data from one QB64 app to another and it generally works but is of course prone to issues if there are other apps running that use the clipboard. Reading and writing to the same files as a way to get it done as well. What I've seen but am not apt with at all is sending data through networking schemes. Anyone have any tips or tricks they've used to do this?

Print this item

  A window with scrolling text in both directions
Posted by: Petr - 09-07-2024, 07:35 PM - Forum: Petr - Replies (5)

I started working on another project, and part of it is the need to have a window on the screen where it will be possible to move the text up and down and left and right. The attached program does this, but in this version you can use arrows with a rectangle showing the position between them for only one window. This is for greater simplicity. In the next version, the program will already include arrows with a slider in such a way that they can be used on multiple windows. (the OldMy variable which is now STATIC would cause problems and will have to be custom for each dialog).

The program supports PgUp and PgDown for scrolling up and down, Home and End are for jumping in the line to the beginning and end of the line, then of course arrows on the keyboard, arrows on the monitor and also by dragging the rectangle between the arrows. After pressing Enter, the function returns the line number where the yellow bar is.

Note the structure of the program. The arrows to control the position of the text in the window can be easily placed anywhere.

Code: (Select All)

'This program will be part of a larger project for SoundEditor.
'The task of this small program is to display a text field in a
'window that allows text to be scrolled left, right, up and down.
'When Enter is pressed, function return row number.

'Note the structure of the program. Arrows with stripes, which are located
'here on the sides of the text window, can be placed independently anywhere.
'Just modify the call to the Arrow function.
'

Dim Shared Samples(1000) As String
For gensamp = 0 To 1000
    For char = 1 To 300 + 125 * Rnd
        a$ = a$ + Chr$(32 + 64 * Rnd)
    Next
    Samples(gensamp) = a$
    a$ = ""
Next


Screen _NewImage(1024, 768, 32)
Cls , _RGB32(240)
Do
    SelectSample = ViewSamples(40, 30, 760, 705, 1, "Samples list:", Samples())
    Locate 1
    If SelectSample > -1 Then Print "Function return record number:"; SelectSample
    _Display
    _Limit 20
Loop

Function ViewSamples (xs As Integer, ys As Integer, xe As Integer, ye As Integer, Mode As _Byte, Title As String, a() As String)
    '    Xs: upper left corner X position
    '    Ys: upper left corner Y position
    '    Xe: bottom right corner X position
    '    Ye: bottom right corner Y position
    '    Mode: if it is zero, no text movement is allowed in the X-axis, and text that would go outside the window
    '          is terminated by three dots, if is 1, is allowed text movement in the X-axis.
    '    Title: Window title
    '    A() is array which contains text

    ViewSamples = -1
    Static VS_Pos 'selector position VERTICAL
    Static ListStart, ListEnd
    Static HS_POS, HS_MAX 'selector position HORIZONTAL

    If HS_MAX = 0 Then
        For t = 0 To UBound(a)
            CurrentLen = Len(a(t))
            If HS_MAX < CurrentLen Then HS_MAX = CurrentLen
        Next t
    End If

    If HS_POS < 1 Then HS_POS = 1

    If xe < xs Then Swap xe, xs
    If ye < ys Then Swap ye, ys

    '----
    'There are two options to jump right to the last position in the text.
    'left it set to always jump to the position of the longest string. Other
    'options (commented out/disallowed here) are that they jump to the end based
    'on the length of a particular string.

    ' If HS_POS > Len(a(VS_Pos)) - ((xe - xs) \ _FontWidth) + 2 Then HS_POS = Len(a(VS_Pos)) - ((xe - xs) \ _FontWidth) + 2
    ' If HS_POS > HS_MAX Then HS_POS = HS_MAX
    If HS_POS > HS_MAX - (xe - xs) \ _FontWidth Then HS_POS = HS_MAX - (xe - xs) \ _FontWidth

    VS_Wdth = xe - xs
    VS_Hght = ye - ys

    Line (xs, ys)-(xe, ye), _RGB32(200), BF
    Line (xs, ys)-(xe, ye), _RGB32(120), B
    If Len(_Trim$(Title$)) > VS_Wdth \ _FontWidth Then
        Title$ = Mid$(Title$, 1, VS_Wdth \ _FontWidth - 3) + "..."
    End If
    _PrintMode _KeepBackground
    Color _RGB32(0)
    _PrintString (xs + VS_Wdth \ 2 - _PrintWidth(Title$) \ 2, ys), Title$
    Line (xs, ys + _FontHeight)-(xe, ys + _FontHeight), _RGB32(120)

    If VS_Pos > ListEnd - 1 Then
        Nr_lines = (ye - ys) \ _FontHeight
        ListStart = VS_Pos - Nr_lines + 3
    End If

    If ListStart > 3 + UBound(a) - VS_Hght \ _FontHeight Then ListStart = 3 + UBound(a) - VS_Hght \ _FontHeight

    If VS_Pos < ListStart Then ListStart = VS_Pos
    If ListStart < 0 Then ListStart = 0

    ListEnd = ListStart + VS_Hght \ _FontHeight
    If VS_Hght \ _FontHeight Mod _FontHeight Then ListEnd = ListEnd - 3
    If ListEnd > UBound(a) Then ListEnd = UBound(a)

    i = 0
    _PrintMode _FillBackground
    For s = ListStart To ListEnd
        If VS_Pos = s Then Color _RGB32(0), _RGB32(255, 255, 0) Else Color _RGB32(0), _RGB32(200)
        Select Case Mode
            Case 0
                If Len(a(s)) > VS_Wdth \ _FontWidth - 1 Then
                    a$ = Mid$(a(s), 1, VS_Wdth \ _FontWidth - 4) + "..."
                Else
                    a$ = a(s)
                End If
            Case 1
                '  If Len(a(s)) > VS_Wdth \ _FontWidth - 1 Then 'if is used this conditon so rows, which lenght is not bigger than window width, are not scrolled to left
                b$ = a(s) + String$(HS_MAX - Len(_Trim$(a(s))), Chr$(32))
                a$ = Mid$(b$, HS_POS, VS_Wdth \ _FontWidth - 1)
                '  Else
                '  a$ = a(s)
                ' End If
        End Select
        _PrintString (xs + 5, 5 + ys + _FontHeight + i * _FontHeight), a$
        i = i + 1
    Next

    'Keyboard support
    k& = _KeyHit

    If Mode Then
        XArrow = Arrow(xs + 2, ye + 4, xe - xs - 2, 1, HS_MAX, HS_POS) 'modify this two lines (XArrow and YArrow) and move scrooll bars
    End If '                                                            and arrows to other place on the screen

    YArrow = Arrow(xe + 2, ys, ye - ys, -1, UBound(a), VS_Pos)


    VS_Pos = VS_Pos + YArrow
    HS_POS = HS_POS + XArrow

    Select Case k&
        Case 18432: VS_Pos = VS_Pos - 1 'arrow up
        Case 20480: VS_Pos = VS_Pos + 1 'arrow down
        Case 13: ViewSamples = VS_Pos: Exit Function
        Case 18688: VS_Pos = VS_Pos - (ye - ys) \ _FontHeight 'PgUp
        Case 20736: VS_Pos = VS_Pos + (ye - ys) \ _FontHeight 'PgDn

        Case 19200: HS_POS = HS_POS - 1 'arrow left
        Case 19712: HS_POS = HS_POS + 1 'arrow right
        Case 18176: HS_POS = 1 '        home
        Case 20224: HS_POS = HS_MAX '    end
    End Select
    If VS_Pos < 0 Then VS_Pos = 0
    If VS_Pos > UBound(a) Then VS_Pos = UBound(a)
End Function

Function Arrow (Xs As Integer, Ys As Integer, Lenght As Integer, Typ As _Byte, SizeOf As Long, SizeNow As Long)
    Arrow = 0
    Static OldMy

    'function draw a rectangular field on the axis with arrows at the end.

    'SizeOf:  maximum size (number of total records in array or lenght of the longest string)
    'SizeNow:  current position number (number of the record in the field or number of the position in the string from the left)
    'Xs:      left upper corner X axis position
    'Ys:      left upper corner Y axis position
    'Lenght:  lenght (width for Typ = 1 or height for typ = -1) for scroll bar with arrows in pixels
    'Typ:      1 is for horizontal dialog (scrollbar in X axis)
    '        -1 is for vertical dialog (scrollbar in Y axis)


    While _MouseInput
    Wend

    MX = _MouseX
    MY = _MouseY
    MB = _MouseButton(1)


    Select Case Typ
        Case -1 '                this is for Y axis (vertical dialog)
            X1 = Xs: X2 = Xs + 7 'up arrow
            Y1 = Ys: Y2 = Ys + 12

            X3 = X1: X4 = X2
            Y3 = Ys + Lenght - 12: y4 = Ys + Lenght 'down arrow



            'logic - up arrow
            MouseInUP = 0
            UpArrowColor~& = _RGB32(96)
            If MX > X1 And MX < X2 Then
                If MY > Y1 And MY < Y2 Then
                    If MB Then Arrow = -1
                    UpArrowColor~& = _RGB32(75)
                    Line (X1, Y1)-(X2, Y2), _RGB32(190), BF
                    MouseInUP = 1
                End If
            End If

            If MouseInUP = 0 Then Line (X1, Y1)-(X2, Y2), _RGB32(250), BF
            'end for logic up arrow


            'logic down arrow
            MouseInDN = 0
            DnArrowColor~& = _RGB32(96)
            If MX > X3 And MX < X4 Then
                If MY > Y3 And MY < y4 Then
                    If MB Then Arrow = 1
                    DnArrowColor~& = _RGB32(75)
                    Line (X3, Y3)-(X4, y4), _RGB32(190), BF
                    MouseInDN = 1
                End If
            End If

            If MouseInDN = 0 Then Line (X3, Y3)-(X4, y4), _RGB32(250), BF
            'end for logic down arrow


            'arrow size: 7x6 pixels
            Restore arrbin
            For X = 0 To 6
                For Y = 0 To 5
                    Read Z
                    If Z Then
                        PSet (Xs + X, Ys + Y), UpArrowColor~& 'sipka nahoru
                        PSet (Xs + X, Ys - Y + Lenght), DnArrowColor~& 'sipka dolu
                    End If
            Next Y, X


            Line (Xs - 2, Ys - 2)-(Xs + 9, Ys + Lenght + 2), _RGB32(100), B 'outter line

            'Description of the inner rectangle:

            'If you can see all the lines of text in the window, the rectangle is over the entire slider.
            'If you can only see 50 percent of the text in the window, the rectangle is exactly halfway up the slider.
            'The length of the rectangle is determined by calculating percentages.
            'If you see 10 percent of the text in the window (100 percent is the maximum size of the field
            'passed - we are talking about scrolling up and down), then the length of the displayed rectangle will be
            'exactly 10 percent of the length between the arrows of the dialog box. However, arrows are also drawn
            'in this length, therefore the length between the upper and lower border of the dialog is reduced
            'by 16 pixels (8 pixels for one arrow). This length is then the basis of 100 percent in pixels for calculating
            'the length of the rectangle between the arrows.

            arrbin: 'arrow image descriptor point by point
            Data 0,0,0,1,1,1,0,0,1,1,1,0,0,1,1,1,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,1,0,0,0,0,1,1,1

            Visible = (Lenght \ _FontHeight) - 2
            PointerLenPercent = Visible / SizeOf
            If PointerLenPercent > 1 Then PointerLenPercent = 1

            RectangleSize = PointerLenPercent * (Lenght - 16)

            RectanglePos = Int(Ys + 8 + (Lenght - 16 - RectangleSize) * SizeNow / SizeOf)

            RecTangleColor~& = _RGB32(200)

            'To increase the speed, the percentage of the height that the mouse click came from
            ' is calculated here. This will determine which record in the field it corresponds
            ' to (for example, in a dialog with a height of 100 pixels, you click on a position
            ' 20 pixels from the top, that is 20 percent. The passed field has a thousand records.
            ' 20 percents of a thousand records is 200, so you want to see position 200 Because the
            'dialog knows which position you are in, it will return the difference between the current
            'position in the field and the calculated position in the field (for example, if you are at
            ' position 50 when you click the mouse in the bar, the program will return the value 150 )

            'condition for move by clicking to rectangle in scrollbar
            If MX > Xs - 70 And MX < Xs + 70 Then
                If MY >= RectanglePos - 20 And MY <= RectanglePos + RectangleSize + 20 Then
                    RecTangleColor~& = _RGB32(75)
                    If MB Then

                        PercentAm = (MY - Ys - 8) / (Lenght - 16)
                        Iam = PercentAm * SizeOf
                        arr = Iam - SizeNow

                        Arrow = Int(arr)
                    End If
                End If
            End If

            Line (Xs + 1, Ys + 6)-(Xs + 6, Ys + 6 + Lenght - 16), _RGB32(255), BF 'clear area before placing rectangle to new position
            Line (Xs + 1, RectanglePos)-(Xs + 6, RectanglePos + RectangleSize), RecTangleColor~&, BF

        Case 1
            'Scrollbar to left and to right in X axis

            X1 = Xs: X2 = Xs + 12 'left arrow
            Y1 = Ys - 1: Y2 = Ys + 8

            X3 = X1 + Lenght - 12: X4 = X1 + Lenght
            Y3 = Ys - 1: y4 = Ys + 8 'right arrow


            'logic - left arrow
            MouseInUP = 0
            LeftArrowColor~& = _RGB32(96)
            If MX > X1 And MX < X2 Then
                If MY > Y1 And MY < Y2 Then
                    If MB Then Arrow = -1
                    LeftArrowColor~& = _RGB32(75)
                    Line (X1, Y1)-(X2, Y2), _RGB32(190), BF
                    MouseInUP = 1
                End If
            End If

            If MouseInUP = 0 Then Line (X1, Y1)-(X2, Y2), _RGB32(250), BF
            'logic left arrow - end


            'logic right arrow
            MouseInDN = 0
            RightArrowColor~& = _RGB32(96)
            If MX > X3 And MX < X4 Then
                If MY > Y3 And MY < y4 Then
                    If MB Then Arrow = 1
                    RightArrowColor~& = _RGB32(75)
                    Line (X3, Y3)-(X4, y4), _RGB32(190), BF
                    MouseInDN = 1
                End If
            End If

            If MouseInDN = 0 Then Line (X3, Y3)-(X4, y4), _RGB32(250), BF
            'logic right arrow - end

            'arrow size is 7x6 pixels
            Restore arrbin2
            For X = 0 To 5
                For Y = 0 To 6
                    Read Z1
                    If Z1 Then
                        PSet (Xs + X, Ys + Y), LeftArrowColor~& 'arrow up
                        PSet (Xs + Lenght - X, Ys + Y), RightArrowColor~& 'arrow down
                    End If
            Next Y, X

            Line (Xs - 2, Ys - 2)-(Xs + Lenght + 2, Ys + 9), _RGB32(100), B 'outter line

            'The calculation of the size of the rectangle inside the slider is similar to the previous case:
            'First, the length of the longest string in the array is determined (see line 46 for the calculation of
            'the variable HS_MAX which is then passed to the function as a parameter) and then the same procedure
            'is followed. You click the mouse in the rectangle, it calculates how many percent from the left edge
            'it is, the same number of percent in the length of the chain is calculated, the default shift from
            'left to right is taken into account, and that is subtracted.

            'Example. You are on third posiiton from the left. You click in the rectangle.
            'According to the position of the mouse in the Y axis, it is calculated that you
            'click 11 percent away from the position Ys + 8 (8 pixels occupied by the arrow).
            'So you want to get to the 11 percent position on the X axis in the string text.
            'This means that if, for example, the variable HS_MAX, which is passed to the function
            'by the SizeOf parameter, is 250, then the longest string has 250 characters. 11 percents
            'of 250 characters is 28 characters after rounding. Since you are at position 3, the function
            'returns an offset of 25 characters.

            'arrow image data point by point
            arrbin2:
            Data 0,0,0,1,0,0,0,0,0,1,1,1,0,0,0,1,1,1,1,1,0,1,1,1,0,1,1,1,1,1,0,0,0,1,1,1,0,0,0,0,0,1

            Visible = ((Lenght - 16) \ _FontWidth) '        how much characters is visible in window
            PointerLenPercent = Visible \ (SizeOf / 100) '  how much percents it is (SizeOf is longest string lenght)
            PointerLenPercent = PointerLenPercent / 100
            If PointerLenPercent > 1 Then PointerLenPercent = 1

            RectangleSize = PointerLenPercent * (Lenght - 16) 'rectangle lenght in slider
            RectanglePos = Int(Xs + 8 + (Lenght - 16) * (SizeNow / SizeOf)) 'rectangle positon in slider

            RecTangleColor~& = _RGB32(200)

            If MX >= RectanglePos - RectangleSize - 16 And MX <= RectanglePos + RectangleSize + 16 Then
                If MY > Ys - 5 And MY < Ys + 16 Then
                    RecTangleColor~& = _RGB32(75)
                    If MB Then
                        PercentAm = (MX - Xs - 8) / (Lenght - 16)
                        Iam = PercentAm * SizeOf
                        arr = Iam - SizeNow
                        Arrow = Int(arr)
                    End If
                End If
            End If
            Line (Xs + 8, Ys - 1)-(Xs + Lenght - 8, Ys + 8), _RGB32(255), BF 'clear area before draw new rectangle to new position
            Line (RectanglePos, Ys)-(RectanglePos + RectangleSize, Ys + 8), RecTangleColor~&, BF
    End Select
End Function

Print this item

  Assigning Date$/Time$ does not wotk
Posted by: eoredson - 09-07-2024, 03:54 AM - Forum: Help Me! - Replies (15)

Hi,

Its nice that you can now assign values to Date$ and Time$ such as:

Code: (Select All)

x$ = Date$
Print "Current date "; x$
Date$ = "09-10-2024"
Print "New date "; Date$
Date$ = x$
Print "Original date "; Date$

t$ = Time$
Print "Current time "; t$
Time$ = "00:00:00"
Print "New time "; Time$
Time$ = t$
Print "Original time "; Time$
End

But they don't seem to do anything...

Erik.

Print this item

  A little program in the making
Posted by: Frederick - 09-07-2024, 12:49 AM - Forum: Programs - No Replies


.bas   FCEXT+.bas (Size: 24.1 KB / Downloads: 33) its a text file and image file compare program.

Print this item

  Is it possible to make a _SNDNEW song this way?
Posted by: Dav - 09-07-2024, 12:16 AM - Forum: Help Me! - Replies (7)

Here's an old program I made at the old forum before I knew PLAY could play more than one note at a time.  It used _SNDRAW to build notes and play them from the sound buffer.  Now that QB64PE has _SNDNEW,_MEMSOUND, etc. I wondered if this program can be used with those somehow.

Instead of playing with _SNDRAW like this, Is it possible to feed the data to a _SNDNEW memory instead so I could have the song with a handle for using it with _SNDPLAY controls?

I thought perhaps this music generator can be useful again for making background songs and play them using _SNDPLAY, and also still have PLAY & SOUND available too for sounds as well, like sound effects.

- Dav   

Code: (Select All)
'==============
'SNDRAWPLAY.BAS v2.0
'==============
'Attempting a PLAY-like song format using _SNDRAW
'Plays notes and allows more than one note to sound at the same time.
'Can play notes in the background.
'Coded By Dav, JAN/2021

'All 88 notes are available.
'Regular notes are lowercase (d4), Sharp notes are upper (D4).
'You can play a notes like this: f3 g3 a3 A3 cf d4 e4 f4
'Play a chord of notes by grouping inside (), like: (c4 e4 g4)

'Assign current note/rest length values like this...
'WN = Whole note, HN = Half note, DQ = Dotted quarter note
'QN = Quarter note, EN = Eighth note, SN = Sixteenth note

'Rests - nothing played, but time continues
'RN = Rest note.  Uses current note length value set.
'For example, to rest a quarter note, do this:
'QN RN

'Assign Tempos like this (always must be in 4 characters):
'T120  ... or T060  ...  or  T100

'Assign current meter (for whole length value to work)
'M3  (thats for 3/4)....  M4  (Thats for 4/4)

'========================================================

'=== Playing two octaves of all notes c3 to c5...
'Set tempo 120, meter 4/4, set sixteen note value
SPLAY "t160 m4 sn c3C3d3D3e3f3F3g3G3a3A3b3c4C4d4D4e4f4F4g4G4a4A4b4c5"

Do
    Color Rnd * 16
    Print "Testing all notes...c3 to c5..."
Loop While _SndRawLen
_SndRawDone


'=== Playing a background song.... Silent Night.,,,

s$ = "t100 m3" 'tempo 100, 3/4 meter
s$ = s$ + "dq(c4e4g4) en(c4f4a4) qn(c4e4g4) wn(g3c4e4)" 'silent night
s$ = s$ + "dq(c4e4g4) en(c4f4a4) qn(c4e4g4) wn(g3c4e4)" 'holy night
s$ = s$ + "hn(d5b4g4) qn(d5b4g4) wn(b4g4d4)" 'all is calm
s$ = s$ + "hn(c5e4g4) qn(c5e4g4) wn(g4e4c4)" 'all is bright
s$ = s$ + "hn(c4f4a4) qn(c4f4a4) dq(c5a4f4) en(b4g4e4) qn(a4f4d4)" 'round yon virgin
s$ = s$ + "dq(c4e4g4) en(c4f4a4) qn(c4e4g4) wn(g3c4e4)" 'mother and child
s$ = s$ + "hn(c4f4a4) qn(c4f4a4) dq(c5a4f4) en(b4g4e4) qn(a4f4d4)" 'holy infant so
s$ = s$ + "dq(c4e4g4) en(c4f4a4) qn(c4e4g4) wn(g3c4e4)" 'tender and mild
s$ = s$ + "hn(d5b4g4) qn(d5b4g4) dq(f5d5b4) en(d5b4g4) qn(b4g4f4)" 'sleep in heavenly
s$ = s$ + "hn(c5g4e4) qn(c5g4e4) hn(e5c5g4) qnrn" 'peace....
s$ = s$ + "qn(c5g4e4) qn(g4e4c4) qn(e4c4g3) dq(g4d4b3) en(f4d4b3) qn(d4b3f3)" 'sleep in heavenly
s$ = s$ + "wn(c4g3e3) rn"

SPLAY s$

Do
    Color Rnd * 16
    Print "Silent Night ";
    If InKey$ <> "" Then Exit Do
Loop While _SndRawLen
_SndRawDone

End




Sub SPLAY (Music$)

    rate = _SndRate

    'Set Defaults, just in case empty
    If Tempo = 0 Then Tempo = 60
    If Meter = 0 Then Meter = 3
    If NoteValue = 0 Then NoteValue = 1

    cur = 1

    Do

        'skip any spaces
        If Mid$(Music$, cur, 1) = " " Then cur = cur + 1

        'Check for tempo
        If UCase$(Mid$(Music$, cur, 1)) = "T" Then
            cur = cur + 1
            Tempo = Val(Mid$(Music$, cur, 3)): cur = cur + 3
        End If

        'Check for Meter
        If UCase$(Mid$(Music$, cur, 1)) = "M" Then
            cur = cur + 1
            Meter = Val(Mid$(Music$, cur, 1)): cur = cur + 1
        End If

        'Get notevalue
        Select Case UCase$(Mid$(Music$, cur, 2))
            Case Is = "DQ": cur = cur + 2: NoteValue = 1.5
            Case Is = "EN": cur = cur + 2: NoteValue = .5
            Case Is = "QN": cur = cur + 2: NoteValue = 1
            Case Is = "HN": cur = cur + 2: NoteValue = 2
            Case Is = "WN": cur = cur + 2
                If Meter = 3 Then NoteValue = 3 Else NoteValue = 4
            Case Is = "SN": cur = cur + 2: NoteValue = .25
        End Select

        'If regular note/rest found (not a group)
        Select Case Mid$(Music$, cur, 2)
            Case Is = "a0": note = 27.50: cur = cur + 2: GoSub LoadNote
            Case Is = "A0": note = 29.14: cur = cur + 2: GoSub LoadNote
            Case Is = "b0": note = 30.87: cur = cur + 2: GoSub LoadNote
            Case Is = "c1": note = 32.70: cur = cur + 2: GoSub LoadNote
            Case Is = "C1": note = 34.65: cur = cur + 2: GoSub LoadNote
            Case Is = "d1": note = 36.71: cur = cur + 2: GoSub LoadNote
            Case Is = "D1": note = 38.89: cur = cur + 2: GoSub LoadNote
            Case Is = "e1": note = 41.20: cur = cur + 2: GoSub LoadNote
            Case Is = "f1": note = 43.65: cur = cur + 2: GoSub LoadNote
            Case Is = "F1": note = 46.25: cur = cur + 2: GoSub LoadNote
            Case Is = "g1": note = 49.00: cur = cur + 2: GoSub LoadNote
            Case Is = "G1": note = 51.91: cur = cur + 2: GoSub LoadNote
            Case Is = "a1": note = 55.00: cur = cur + 2: GoSub LoadNote
            Case Is = "A1": note = 58.27: cur = cur + 2: GoSub LoadNote
            Case Is = "b1": note = 61.74: cur = cur + 2: GoSub LoadNote
            Case Is = "c2": note = 65.41: cur = cur + 2: GoSub LoadNote
            Case Is = "C2": note = 69.30: cur = cur + 2: GoSub LoadNote
            Case Is = "d2": note = 73.42: cur = cur + 2: GoSub LoadNote
            Case Is = "D2": note = 77.78: cur = cur + 2: GoSub LoadNote
            Case Is = "e2": note = 82.41: cur = cur + 2: GoSub LoadNote
            Case Is = "f2": note = 87.31: cur = cur + 2: GoSub LoadNote
            Case Is = "F2": note = 92.50: cur = cur + 2: GoSub LoadNote
            Case Is = "g2": note = 98.00: cur = cur + 2: GoSub LoadNote
            Case Is = "G2": note = 103.83: cur = cur + 2: GoSub LoadNote
            Case Is = "a2": note = 110.00: cur = cur + 2: GoSub LoadNote
            Case Is = "A2": note = 116.54: cur = cur + 2: GoSub LoadNote
            Case Is = "b2": note = 123.47: cur = cur + 2: GoSub LoadNote
            Case Is = "c3": note = 130.81: cur = cur + 2: GoSub LoadNote
            Case Is = "C3": note = 138.59: cur = cur + 2: GoSub LoadNote
            Case Is = "d3": note = 146.83: cur = cur + 2: GoSub LoadNote
            Case Is = "D3": note = 155.56: cur = cur + 2: GoSub LoadNote
            Case Is = "e3": note = 164.81: cur = cur + 2: GoSub LoadNote
            Case Is = "f3": note = 174.61: cur = cur + 2: GoSub LoadNote
            Case Is = "F3": note = 185.00: cur = cur + 2: GoSub LoadNote
            Case Is = "g3": note = 196.00: cur = cur + 2: GoSub LoadNote
            Case Is = "G3": note = 207.65: cur = cur + 2: GoSub LoadNote
            Case Is = "a3": note = 220.00: cur = cur + 2: GoSub LoadNote
            Case Is = "A3": note = 233.08: cur = cur + 2: GoSub LoadNote
            Case Is = "b3": note = 246.94: cur = cur + 2: GoSub LoadNote
            Case Is = "c4": note = 261.63: cur = cur + 2: GoSub LoadNote
            Case Is = "C4": note = 277.18: cur = cur + 2: GoSub LoadNote
            Case Is = "d4": note = 293.66: cur = cur + 2: GoSub LoadNote
            Case Is = "D4": note = 311.13: cur = cur + 2: GoSub LoadNote
            Case Is = "e4": note = 329.63: cur = cur + 2: GoSub LoadNote
            Case Is = "f4": note = 349.23: cur = cur + 2: GoSub LoadNote
            Case Is = "F4": note = 369.99: cur = cur + 2: GoSub LoadNote
            Case Is = "g4": note = 392.00: cur = cur + 2: GoSub LoadNote
            Case Is = "G4": note = 415.30: cur = cur + 2: GoSub LoadNote
            Case Is = "a4": note = 440.00: cur = cur + 2: GoSub LoadNote
            Case Is = "A4": note = 466.16: cur = cur + 2: GoSub LoadNote
            Case Is = "b4": note = 493.88: cur = cur + 2: GoSub LoadNote
            Case Is = "c5": note = 523.25: cur = cur + 2: GoSub LoadNote
            Case Is = "C5": note = 554.37: cur = cur + 2: GoSub LoadNote
            Case Is = "d5": note = 587.33: cur = cur + 2: GoSub LoadNote
            Case Is = "D5": note = 622.25: cur = cur + 2: GoSub LoadNote
            Case Is = "e5": note = 659.25: cur = cur + 2: GoSub LoadNote
            Case Is = "f5": note = 698.46: cur = cur + 2: GoSub LoadNote
            Case Is = "F5": note = 739.99: cur = cur + 2: GoSub LoadNote
            Case Is = "g5": note = 783.99: cur = cur + 2: GoSub LoadNote
            Case Is = "G5": note = 830.61: cur = cur + 2: GoSub LoadNote
            Case Is = "a5": note = 880.00: cur = cur + 2: GoSub LoadNote
            Case Is = "A5": note = 932.33: cur = cur + 2: GoSub LoadNote
            Case Is = "b5": note = 987.77: cur = cur + 2: GoSub LoadNote
            Case Is = "c6": note = 1046.50: cur = cur + 2: GoSub LoadNote
            Case Is = "C6": note = 1108.73: cur = cur + 2: GoSub LoadNote
            Case Is = "d6": note = 1174.66: cur = cur + 2: GoSub LoadNote
            Case Is = "D6": note = 1244.51: cur = cur + 2: GoSub LoadNote
            Case Is = "e6": note = 1318.51: cur = cur + 2: GoSub LoadNote
            Case Is = "f6": note = 1396.91: cur = cur + 2: GoSub LoadNote
            Case Is = "F6": note = 1479.98: cur = cur + 2: GoSub LoadNote
            Case Is = "g6": note = 1567.98: cur = cur + 2: GoSub LoadNote
            Case Is = "G6": note = 1661.22: cur = cur + 2: GoSub LoadNote
            Case Is = "a6": note = 1760.00: cur = cur + 2: GoSub LoadNote
            Case Is = "A6": note = 1864.66: cur = cur + 2: GoSub LoadNote
            Case Is = "b6": note = 1975.53: cur = cur + 2: GoSub LoadNote
            Case Is = "c7": note = 2093.00: cur = cur + 2: GoSub LoadNote
            Case Is = "C7": note = 2217.46: cur = cur + 2: GoSub LoadNote
            Case Is = "d7": note = 2349.32: cur = cur + 2: GoSub LoadNote
            Case Is = "D7": note = 2489.02: cur = cur + 2: GoSub LoadNote
            Case Is = "e7": note = 2637.02: cur = cur + 2: GoSub LoadNote
            Case Is = "f7": note = 2793.83: cur = cur + 2: GoSub LoadNote
            Case Is = "F7": note = 2959.96: cur = cur + 2: GoSub LoadNote
            Case Is = "g7": note = 3135.96: cur = cur + 2: GoSub LoadNote
            Case Is = "G7": note = 3322.44: cur = cur + 2: GoSub LoadNote
            Case Is = "a7": note = 3520.00: cur = cur + 2: GoSub LoadNote
            Case Is = "A7": note = 3729.31: cur = cur + 2: GoSub LoadNote
            Case Is = "b7": note = 3951.07: cur = cur + 2: GoSub LoadNote
            Case Is = "c8": note = 4186.01: cur = cur + 2: GoSub LoadNote
            Case Is = "RN", "rn": note = 0: cur = cur + 2: GoSub LoadNote
        End Select

        'if group of notes found
        If Mid$(Music$, cur, 1) = "(" Then
            cur = cur + 1
            'Grab up until ')' found
            Group$ = ""
            Do
                a$ = Mid$(Music$, cur, 1): cur = cur + 1
                If a$ = ")" Then Exit Do
                If a$ <> " " Then Group$ = Group$ + a$
            Loop

            NumOfNotes = Len(Group$) / 2
            Length = (60 * NoteValue / Tempo)
            For L = 0 To Length * rate Step NumOfNotes

                For N = 1 To Len(Group$) Step 2
                    'fade = EXP(-L / rate * 8)
                    note$ = Mid$(Group$, N, 2)
                    If note$ = "a0" Then _SndRaw Sin((L / rate) * 27.50 * Atn(1) * 8) '* fade.
                    If note$ = "A0" Then _SndRaw Sin((L / rate) * 29.14 * Atn(1) * 8) '* fade.
                    If note$ = "b0" Then _SndRaw Sin((L / rate) * 30.87 * Atn(1) * 8) '* fade.
                    If note$ = "c1" Then _SndRaw Sin((L / rate) * 32.70 * Atn(1) * 8) '* fade.
                    If note$ = "C1" Then _SndRaw Sin((L / rate) * 34.65 * Atn(1) * 8) '* fade.
                    If note$ = "d1" Then _SndRaw Sin((L / rate) * 36.71 * Atn(1) * 8) '* fade.
                    If note$ = "D1" Then _SndRaw Sin((L / rate) * 38.89 * Atn(1) * 8) '* fade.
                    If note$ = "e1" Then _SndRaw Sin((L / rate) * 41.20 * Atn(1) * 8) '* fade.
                    If note$ = "f1" Then _SndRaw Sin((L / rate) * 43.65 * Atn(1) * 8) '* fade.
                    If note$ = "F1" Then _SndRaw Sin((L / rate) * 46.25 * Atn(1) * 8) '* fade.
                    If note$ = "g1" Then _SndRaw Sin((L / rate) * 49.00 * Atn(1) * 8) '* fade.
                    If note$ = "G1" Then _SndRaw Sin((L / rate) * 51.91 * Atn(1) * 8) '* fade.
                    If note$ = "a1" Then _SndRaw Sin((L / rate) * 55.00 * Atn(1) * 8) '* fade.
                    If note$ = "A1" Then _SndRaw Sin((L / rate) * 58.27 * Atn(1) * 8) '* fade.
                    If note$ = "b1" Then _SndRaw Sin((L / rate) * 61.74 * Atn(1) * 8) '* fade.
                    If note$ = "c2" Then _SndRaw Sin((L / rate) * 65.41 * Atn(1) * 8) '* fade.
                    If note$ = "C2" Then _SndRaw Sin((L / rate) * 69.30 * Atn(1) * 8) '* fade.
                    If note$ = "d2" Then _SndRaw Sin((L / rate) * 73.42 * Atn(1) * 8) '* fade.
                    If note$ = "D2" Then _SndRaw Sin((L / rate) * 77.78 * Atn(1) * 8) '* fade.
                    If note$ = "e2" Then _SndRaw Sin((L / rate) * 82.41 * Atn(1) * 8) '* fade.
                    If note$ = "f2" Then _SndRaw Sin((L / rate) * 87.31 * Atn(1) * 8) '* fade.
                    If note$ = "F2" Then _SndRaw Sin((L / rate) * 92.50 * Atn(1) * 8) '* fade.
                    If note$ = "g2" Then _SndRaw Sin((L / rate) * 98.00 * Atn(1) * 8) '* fade.
                    If note$ = "G2" Then _SndRaw Sin((L / rate) * 103.83 * Atn(1) * 8) '* fade.
                    If note$ = "a2" Then _SndRaw Sin((L / rate) * 110.00 * Atn(1) * 8) '* fade.
                    If note$ = "A2" Then _SndRaw Sin((L / rate) * 116.54 * Atn(1) * 8) '* fade.
                    If note$ = "b2" Then _SndRaw Sin((L / rate) * 123.47 * Atn(1) * 8) '* fade.
                    If note$ = "c3" Then _SndRaw Sin((L / rate) * 130.81 * Atn(1) * 8) '* fade.
                    If note$ = "C3" Then _SndRaw Sin((L / rate) * 138.59 * Atn(1) * 8) '* fade.
                    If note$ = "d3" Then _SndRaw Sin((L / rate) * 146.83 * Atn(1) * 8) '* fade.
                    If note$ = "D3" Then _SndRaw Sin((L / rate) * 155.56 * Atn(1) * 8) '* fade.
                    If note$ = "e3" Then _SndRaw Sin((L / rate) * 164.81 * Atn(1) * 8) '* fade.
                    If note$ = "f3" Then _SndRaw Sin((L / rate) * 174.61 * Atn(1) * 8) '* fade.
                    If note$ = "F3" Then _SndRaw Sin((L / rate) * 185.00 * Atn(1) * 8) '* fade.
                    If note$ = "g3" Then _SndRaw Sin((L / rate) * 196.00 * Atn(1) * 8) '* fade.
                    If note$ = "G3" Then _SndRaw Sin((L / rate) * 207.65 * Atn(1) * 8) '* fade.
                    If note$ = "a3" Then _SndRaw Sin((L / rate) * 220.00 * Atn(1) * 8) '* fade.
                    If note$ = "A3" Then _SndRaw Sin((L / rate) * 233.08 * Atn(1) * 8) '* fade.
                    If note$ = "b3" Then _SndRaw Sin((L / rate) * 246.94 * Atn(1) * 8) '* fade.
                    If note$ = "c4" Then _SndRaw Sin((L / rate) * 261.63 * Atn(1) * 8) '* fade.
                    If note$ = "C4" Then _SndRaw Sin((L / rate) * 277.18 * Atn(1) * 8) '* fade.
                    If note$ = "d4" Then _SndRaw Sin((L / rate) * 293.66 * Atn(1) * 8) '* fade.
                    If note$ = "D4" Then _SndRaw Sin((L / rate) * 311.13 * Atn(1) * 8) '* fade.
                    If note$ = "e4" Then _SndRaw Sin((L / rate) * 329.63 * Atn(1) * 8) '* fade.
                    If note$ = "f4" Then _SndRaw Sin((L / rate) * 349.23 * Atn(1) * 8) '* fade.
                    If note$ = "F4" Then _SndRaw Sin((L / rate) * 369.99 * Atn(1) * 8) '* fade.
                    If note$ = "g4" Then _SndRaw Sin((L / rate) * 392.00 * Atn(1) * 8) '* fade.
                    If note$ = "G4" Then _SndRaw Sin((L / rate) * 415.30 * Atn(1) * 8) '* fade.
                    If note$ = "a4" Then _SndRaw Sin((L / rate) * 440.00 * Atn(1) * 8) '* fade.
                    If note$ = "A4" Then _SndRaw Sin((L / rate) * 466.16 * Atn(1) * 8) '* fade.
                    If note$ = "b4" Then _SndRaw Sin((L / rate) * 493.88 * Atn(1) * 8) '* fade.
                    If note$ = "c5" Then _SndRaw Sin((L / rate) * 523.25 * Atn(1) * 8) '* fade.
                    If note$ = "C5" Then _SndRaw Sin((L / rate) * 554.37 * Atn(1) * 8) '* fade.
                    If note$ = "d5" Then _SndRaw Sin((L / rate) * 587.33 * Atn(1) * 8) '* fade.
                    If note$ = "D5" Then _SndRaw Sin((L / rate) * 622.25 * Atn(1) * 8) '* fade.
                    If note$ = "e5" Then _SndRaw Sin((L / rate) * 659.25 * Atn(1) * 8) '* fade.
                    If note$ = "f5" Then _SndRaw Sin((L / rate) * 698.46 * Atn(1) * 8) '* fade.
                    If note$ = "F5" Then _SndRaw Sin((L / rate) * 739.99 * Atn(1) * 8) '* fade.
                    If note$ = "g5" Then _SndRaw Sin((L / rate) * 783.99 * Atn(1) * 8) '* fade.
                    If note$ = "G5" Then _SndRaw Sin((L / rate) * 830.61 * Atn(1) * 8) '* fade.
                    If note$ = "a5" Then _SndRaw Sin((L / rate) * 880.00 * Atn(1) * 8) '* fade.
                    If note$ = "A5" Then _SndRaw Sin((L / rate) * 932.33 * Atn(1) * 8) '* fade.
                    If note$ = "b5" Then _SndRaw Sin((L / rate) * 987.77 * Atn(1) * 8) '* fade.
                    If note$ = "c6" Then _SndRaw Sin((L / rate) * 1046.50 * Atn(1) * 8) '* fade.
                    If note$ = "C6" Then _SndRaw Sin((L / rate) * 1108.73 * Atn(1) * 8) '* fade.
                    If note$ = "d6" Then _SndRaw Sin((L / rate) * 1174.66 * Atn(1) * 8) '* fade.
                    If note$ = "D6" Then _SndRaw Sin((L / rate) * 1244.51 * Atn(1) * 8) '* fade.
                    If note$ = "e6" Then _SndRaw Sin((L / rate) * 1318.51 * Atn(1) * 8) '* fade.
                    If note$ = "f6" Then _SndRaw Sin((L / rate) * 1396.91 * Atn(1) * 8) '* fade.
                    If note$ = "F6" Then _SndRaw Sin((L / rate) * 1479.98 * Atn(1) * 8) '* fade.
                    If note$ = "g6" Then _SndRaw Sin((L / rate) * 1567.98 * Atn(1) * 8) '* fade.
                    If note$ = "G6" Then _SndRaw Sin((L / rate) * 1661.22 * Atn(1) * 8) '* fade.
                    If note$ = "a6" Then _SndRaw Sin((L / rate) * 1760.00 * Atn(1) * 8) '* fade.
                    If note$ = "A6" Then _SndRaw Sin((L / rate) * 1864.66 * Atn(1) * 8) '* fade.
                    If note$ = "b6" Then _SndRaw Sin((L / rate) * 1975.53 * Atn(1) * 8) '* fade.
                    If note$ = "c7" Then _SndRaw Sin((L / rate) * 2093.00 * Atn(1) * 8) '* fade.
                    If note$ = "C7" Then _SndRaw Sin((L / rate) * 2217.46 * Atn(1) * 8) '* fade.
                    If note$ = "d7" Then _SndRaw Sin((L / rate) * 2349.32 * Atn(1) * 8) '* fade.
                    If note$ = "D7" Then _SndRaw Sin((L / rate) * 2489.02 * Atn(1) * 8) '* fade.
                    If note$ = "e7" Then _SndRaw Sin((L / rate) * 2637.02 * Atn(1) * 8) '* fade.
                    If note$ = "f7" Then _SndRaw Sin((L / rate) * 2793.83 * Atn(1) * 8) '* fade.
                    If note$ = "F7" Then _SndRaw Sin((L / rate) * 2959.96 * Atn(1) * 8) '* fade.
                    If note$ = "g7" Then _SndRaw Sin((L / rate) * 3135.96 * Atn(1) * 8) '* fade.
                    If note$ = "G7" Then _SndRaw Sin((L / rate) * 3322.44 * Atn(1) * 8) '* fade.
                    If note$ = "a7" Then _SndRaw Sin((L / rate) * 3520.00 * Atn(1) * 8) '* fade.
                    If note$ = "A7" Then _SndRaw Sin((L / rate) * 3729.31 * Atn(1) * 8) '* fade.
                    If note$ = "b7" Then _SndRaw Sin((L / rate) * 3951.07 * Atn(1) * 8) '* fade.
                    If note$ = "c8" Then _SndRaw Sin((L / rate) * 4186.01 * Atn(1) * 8) '* fade.
                Next

            Next

        End If

        If cur >= Len(Music$) Then Exit Do

        'IF INKEY$ <> "" THEN EXIT SUB

    Loop

    Exit Sub

    '=========================================================
    LoadNote:
    '========
    Length = (60 * NoteValue / Tempo)
    For L = 0 To Length * rate
        'fade = Exp(-L / rate * 8)
        If note = 0 Then
            _SndRaw 0
        Else
            _SndRaw Sin((L / rate) * note * Atn(1) * 8) '* fade
        End If
    Next
    Return

End Sub

Print this item