Snowman screen saver playing 17 MIDI Christmas songs
#1
I updated my old Snowman screen saver to test the experimental (and $UNSTABLE) MIDI playback feature of QB64PE.  This is a simple looping animation that plays 17 different Christmas songs continuously.  It's just something nice to have on the screen whenever you need a snowy atmosphere.  

It sure is nice to have MIDI playback in QB64PE, the only negative is that it takes a rather long time to open a MIDI file.  Loading these 17 MIDI files takes a couple minutes on my PC.  I found that MIDI feature is most stable when opening MIDI files at the beginning and leaving them open throughout the program.  Opening/Closing them over and over in the program caused hangups, so I ended up just loading them all at startup and doing a _SNDSTOP when changing to a start new song.

I'll post the code here for the curious, but you will need to download the archive to run it.  You will need QB64PE v3.2 or higher to use the $MIDISOUNDFONT metacommand.  I haven't tested this in Linux yet, but I guess it will work if the Linux version also supports the new MIDI metacommand.

- Dav


.zip   snowman-v103.zip (Size: 710.24 KB / Downloads: 48)

Code: (Select All)
'==========
'SNOWMAN.BAS v1.03
'===========
'Play Snowman animation while playing 17 Christmas songs.
'Coded by Dav for QB64PE, DEC/2022
'ALL MEDIA SOURCES FOUND IN PUBLIC DOMAIN
'
'=======================================================================
'NOTE: THIS PROGRAM REQUIRES QB64-PE v3.2 OR HIGHER TO RUN & USE MIDI
'=======================================================================
'
'CONTROLS:
'           WHILE PLAYING, USE LEFT & RIGHT ARROWS TO SKIP SONGS.
'           ANY OTHER KEY QUITS THE SAVER
'
'The screen saver will start playing a random song.  You an skip up/down
'to different songs using the left/right arrow keys.  Pressing any other
'key will quit the program.
'
'NOTE: It takes a minute or two to load all the MIDI files on startup.
'Please be patient while they load, and enjoythe Christmas screen saver.
'
'=======================================================================

$UNSTABLE:MIDI
PRINT "=============================="
PRINT "SNOWMAN SCREENSAVER FOR QB64PE"
PRINT "(please wait while files load)"
PRINT "=============================="
PRINT
PRINT "Init MIDI soundfont...";
$MIDISOUNDFONT:DEFAULT
PRINT "OK!"

'=== Check the animation file
PRINT "Checking animation file...";
file$ = "snowman.dat"
OPEN file$ FOR BINARY AS #1
IF LOF(1) = 0 THEN
    PRINT "SNOWMAN.DAT NOT FOUND!"
    CLOSE 1: KILL file$
    END
END IF
IF LOF(1) <> 800528 THEN
    PRINT "INVALID SNOWMAN.DAT!"
    CLOSE 1
    END
END IF
PRINT "OK!"

'=== Build the MIDI song list..

trackmax = 17 '17 midi files
DIM song$(1 TO trackmax), songhand&(1 TO trackmax)
'name each one
song$(1) = "frosty.mid"
song$(2) = "hark.mid"
song$(3) = "away.mid"
song$(4) = "angels.mid"
song$(5) = "carol.mid"
song$(6) = "joy.mid"
song$(7) = "deck.mid"
song$(8) = "wethree.mid"
song$(9) = "holynite.mid"
song$(10) = "godrest.mid"
song$(11) = "itcame.mid"
song$(12) = "ohcome.mid"
song$(13) = "noel.mid"
song$(14) = "silent.mid"
song$(15) = "town.mid"
song$(16) = "jingle.mid"
song$(17) = "wewish.mid"

FOR s = 1 TO trackmax
    PRINT "Loading MIDI file"; s; "of"; trackmax; ": "; song$(s); "...";
    songhand&(s) = _SNDOPEN(song$(s), "stream")
    IF songhand&(s) = 0 THEN
        PRINT "Error opening file: "; song$(s)
        END
    END IF
    PRINT "OK!"
NEXT

'=== start playing a random track
RANDOMIZE TIMER
track = INT(RND * trackmax) + 1
_SNDPLAY songhand&(track)


SCREEN 13: _FULLSCREEN _SQUAREPIXELS , _SMOOTH

DO
    SEEK 1, 129
    FOR f% = 1 TO 15
        FF& = SEEK(1): FRM$ = INPUT$(16, 1)
        FrameSize& = CVL(MID$(FRM$, 1, 4))
        chunks% = CVI(MID$(FRM$, 7, 2))
        d$ = INKEY$
        IF d$ <> "" THEN
            SELECT CASE d$
                CASE CHR$(0) + CHR$(77)
                    _SNDSTOP songhand&(track)
                    track = track + 1
                    IF track > trackmax THEN track = 1
                    _SNDPLAY songhand&(track)
                CASE CHR$(0) + CHR$(75)
                    _SNDSTOP songhand&(track)
                    track = track - 1
                    IF track < 1 THEN track = trackmax
                    _SNDPLAY songhand&(track)
                CASE ELSE: EXIT DO
            END SELECT
        END IF
        FOR C% = 1 TO chunks%
            Fpos& = SEEK(1)
            CD$ = INPUT$(6, 1)
            ChunkSize& = CVL(MID$(CD$, 1, 4))
            ChunkType% = CVI(MID$(CD$, 5, 2))
            Fpos& = Fpos& + ChunkSize&
            SELECT CASE ChunkType%
                CASE 11
                    Clr% = 0
                    paks% = ASC(INPUT$(2, 1))
                    FOR d% = 1 TO paks%
                        skip% = ASC(INPUT$(1, 1))
                        change% = ASC(INPUT$(1, 1))
                        IF change% = 0 THEN change% = 256
                        Clr% = Clr% + skip%
                        FOR s% = 1 TO change%
                            OUT &H3C8, Clr%
                            OUT &H3C9, ASC(INPUT$(1, 1))
                            OUT &H3C9, ASC(INPUT$(1, 1))
                            OUT &H3C9, ASC(INPUT$(1, 1))
                            Clr% = Clr% + 1
                        NEXT
                    NEXT
                CASE 12
                    skip% = CVI(INPUT$(2, 1))
                    change% = CVI(INPUT$(2, 1))
                    FOR y% = skip% TO change% + (skip% - 1)
                        ppos& = SEEK(1)
                        C$ = INPUT$(500, 1): m% = 1
                        paks% = ASC(MID$(C$, m%, 1)): m% = m% + 1: x% = 0
                        FOR d% = 1 TO paks%
                            s% = ASC(MID$(C$, m%, 1))
                            p% = ASC(MID$(C$, m% + 1, 1))
                            m% = m% + 2: x% = x% + s%
                            IF p% > 127 THEN
                                p% = (256 - p%)
                                LINE (x%, y%)-STEP(p% - 1, 0), ASC(MID$(C$, m%, 1))
                                x% = x% + p%: m% = m% + 1
                            ELSE
                                Row$ = MID$(C$, m%, p%)
                                m% = m% + p%
                                FOR g% = 0 TO p% - 1
                                    PSET (x% + g%, y%), ASC(MID$(Row$, g% + 1, 1))
                                NEXT
                                x% = x% + p%
                            END IF
                        NEXT
                        SEEK #1, ppos& + m% - 1: C$ = ""
                    NEXT
                CASE 16
                    x% = 0
                    FOR y% = 0 TO 199
                        Row$ = INPUT$(320, 1): p% = 320
                        FOR g% = 0 TO p% - 1
                            PSET (x% + g%, y%), ASC(MID$(Row$, g% + 1, 1))
                        NEXT
                    NEXT
                CASE ELSE: CLOSE 1: EXIT DO
            END SELECT
            SEEK #1, Fpos&
        NEXT
        SEEK 1, FF& + FrameSize&
        _DISPLAY
        _LIMIT 12
    NEXT

    IF NOT _SNDPLAYING(songhand&(track)) THEN
        _SNDSTOP songhand&(track)
        track = track + 1
        IF track > trackmax THEN track = 1
        _SNDPLAY songhand&(track)
    END IF

LOOP

_SNDSTOP songhand&(track)
_SNDCLOSE songhand&(track)

CLOSE 1
SYSTEM

Find my programs here in Dav's QB64 Corner
Reply
#2
WOW! That's a keeper. Nice to have some Christmas music while I code out Keywords of the Christmas Season.

I used Alt+Enter a couple of times to reduce it to a small window while writing this post.

Just one matter of utmost concern. Your title title led me to believe there would be an old snowman in the screen saver. All I see is Steve, in a funny hat, sweeping the snow off my New England rental property.

Pete +2
Reply
#3
Excellent!

This worked on Manjaro KDE without problems. And without Wine. Smile

Some people might have to lower the volume a lot when listening with headphones LOL.

Also Dav it's a good thing you called it "screensaver" because some kids might start being put off by the long "loading time". Tell one of those kids, "Just keep doing your stuff for like 3 minutes because it suddenly pops up and plays."
Reply
#4
@Dav Here's a trick for you to try with the upgraded version of QB64-PE:

Code: (Select All)
    songhand&(s) = _SndOpen(song$(s), "stream")

Change the line in your code where you open the songs to look like the above, and then give it a run.  Let me know how long it takes to load the songs for you then, and whether or not they even play for you.  As you mentioned in your own post, these features are still $UNSTABLE and need as much testing and feedback as we can give them.  Wink
Reply
#5
@Pete, thanks for trying it out!

@mnrvovrfc: Thanks for testing it in Linux.  Glad it works.

@SMcNeill:  Thanks!  Wow, what a speed increase adding that.  Less than a second and they all load and play fine.   I'm going to update the download with the edit code.

- Dav

Find my programs here in Dav's QB64 Corner
Reply
#6
I updated the download with Steve's change, or you can edit the code you already have.  Cool to have MIDI playback again in QB64!

- Dav

Find my programs here in Dav's QB64 Corner
Reply
#7
(12-17-2022, 03:06 PM)Dav Wrote: @Pete, thanks for trying it out!

@mnrvovrfc: Thanks for testing it in Linux.  Glad it works.

@SMcNeill:  Thanks!  Wow, what a speed increase adding that.  Less than a second and they all load and play fine.   I'm going to update the download with the edit code.

- Dav

Glad it worked as advertised for you!

Some info on "stream", as per our wiki: https://qb64phoenix.com/qb64wiki/index.php/SNDOPEN
  • The literal or variable STRING capabilities$ is optional but can be STREAM (version 3.1.0 and up). Anything else is ignored.
  • Specifying STREAM as a second parameter will "stream" the sound into memory rather than fully decoding it. This is good when we want to play long sounds as background music and want to avoid loading delays.
  • Short sounds should not be loaded using STREAM. Also, _MEMSOUND will not work for sounds loaded using STREAM.
Reply
#8
I never noticed that parameter.  Glad to know about it.  Thanks.

- Dav

Find my programs here in Dav's QB64 Corner
Reply
#9
very nice Dav Smile
Reply
#10
(12-17-2022, 03:58 PM)Jack Wrote: very nice Dav Smile

Thanks, Jack.

Hey Steve, or Pete, I just noticed there is a Christmas code section now.  If you would like to move this into there, please do.  Sorry I should have posted this in there.

- Dav

Find my programs here in Dav's QB64 Corner
Reply




Users browsing this thread: 1 Guest(s)