QB64 Phoenix Edition
Mindless pattern music (requires OpenMPT) - Printable Version

+- QB64 Phoenix Edition (https://qb64phoenix.com/forum)
+-- Forum: QB64 Rising (https://qb64phoenix.com/forum/forumdisplay.php?fid=1)
+--- Forum: Code and Stuff (https://qb64phoenix.com/forum/forumdisplay.php?fid=3)
+---- Forum: Works in Progress (https://qb64phoenix.com/forum/forumdisplay.php?fid=9)
+---- Thread: Mindless pattern music (requires OpenMPT) (/showthread.php?tid=1554)



Mindless pattern music (requires OpenMPT) - mnrvovrfc - 03-16-2023

I'm just going to throw this into this place on the hope somebody out there could make use of it.

TL;DR It's a monophonic sequence creator for OpenMPT. It creates text-file patterns, each one to paste into the tracker.

It could use some improvements:
* do something about the hard-coded response file name and the output directory and filenames.
* be able to change the instrument command away from the first one.
* do something for those people who like wide open spaces in their piano music. The program as presented could fake arpeggiators very well.
* allow notes-off in the gaps.
* create polyphonic sequences, maybe the "main" one less accented than the other tracks.
* instead of accent, choose volume commands from a list. Optionally make them the same for the "piano roll".
* if working with samples, support some effect commands like pitch-bend, vibrato and retrigger. Yes I have done this and more but that program is way more complicated than this one. "Gotta have my edge...," Barry Bonds said once ROFLMAO.

An even better program would be to figure out Impulse Tracker module format, even with one "instrument" which is a looped sinewave, and create one of those things so you guys could play it back with a QB64(PE) program or with one of the players like VLC that supports music tracker modules. "MOD" looks easy but it's not, and the sound quality tends to be poor, and the format is restrictive because pretty much only two octaves are supported and the volume column cannot be used.

One easy way to check it out is to create the "omptchblende.txt" in the same directory as the executable:
* set the "omptchblende.txt" to the following:
Code: (Select All)
C-4;C-4;C-4;C-4;E-4;G#4
64
64
64
7
* This is only three different notes of the same octave, with "middle C" being chosen most often, and with most notes emphasized the strongest (like "ff" in sheet music, while others are like "mp" or "mf"). This will create one pattern which is 64 rows long. It will be called "pat01.txt" found in your Documents directory.
* download OpenMPT from https://openmpt.org
* if on Windows10 I recommend not downloading "legacy" version, unless you're full of VST plug-ins like I am LOL -- just choose either 32-bit or 64-bit option which is shown topmost on the download page.
* on Linux make sure you installed Wine and ran "winecfg", or for the users most experienced with doing this, set up a Wine "prefix". On some distros based on Arch Linux, if you opt for the 32-bit OpenMPT also install the 32-bit version of Portaudio: must have the repository data fully updated before doing on the terminal: "sudo pacman -S lib32-portaudio". If this is not done the WASAPI option won't be shown and the program will fail to produce any sound. This is unnecessary if you picked the 64-bit Windows application, again, the choice is whether or not you have to use VST2 plug-ins which come only in 32-bit or only in 64-bit. DO NOT CARE ABOUT THE "Wine" TAB OF THE PROGRAM PREFERENCES, it does not do what you might expect and you could mess up your installation!
* install it, or copy "portable" version anywhere you like in your user area, check sound card settings, shouldn't be many problems on Windows.
* WATCH OUT FOR YOUR HEARING LEVELS! Set the volume preferably to something near minimum. If you can't hear anything while using this program, SLOWLY raise the volume.
* Use File/New/MPTM. Could press the empty sheet icon on main toolbar but it creates an "IT" module which might not be convenient for this exercise. You might want to maximize the document window within app window.
* visit sample tab or press [ALT][S]. Choose the sun on the toolbar just above the empty waveform view. Accept whatever settings it says to create a waveform buffer. Then choose the pencil and just mouse-click and drag around to draw your own waveform!
* if you know a lot more than this you could import a looped multisample, or you could create an "OPL" instrument. But for "OPL" must be either "S3M" or "MPTM" format! Could also import from a SoundFont (SF2) but doesn't support layered patches. In other words if you loved that piano-string you heard in somebody's song and it's packed into a SoundFont, you could have either the piano or the string but not both. You'll have to load each component in their separate sample slots and play them together. If you know enough about "studio ways" the two multisamples could be mixed but that's less desireable sometimes. How about a combination that responds by music keyboard note (wood bass) and one that does not (ride cymbal), like that "jazz bass" patch I found in a Yamaha keyboard somewhere?
* press keyboard keys below the numbers, you should get the looped sample played and sustained at different pitches. Press [F8] or the square button on the transport to halt the sound.
* now change to pattern view or press [ALT][P].
* if you haven't done so already, load the pattern text file "pat01.txt" with Notepad or other good text editor, and copy the whole thing into the clipboard.
* switch to OpenMPT, focus on the first row of the first track with the mouse pointer, then paste.
* press play button on the transport or press [F5].
* if it sounds too "legato" for you LOL you could add notes-off to the gaps. Now I'm not sure what is the key for note-off, probably grave-accent because I have my own key map that I slowly modified for years using this program.
* alternatively with some notes try putting "SC1" on the right-hand-most column inside the track (channel). Type "S", then use right-arrow key, then type "C1" until it reads "SC1". After this is done the edit cursor should be at the right-hand edge of the track (channel). Play back and that note, and others modified this way, will sound off for a very short time! Might not even be heard. To do something about it, you will have to create an instrument related to that sample, but this is not a tutorial about composing music in a given tracker LOL.
* instead of the above to enter "SC1" could double-click near the pillar of the right-hand side of the channel, or press the "application" key between [ALT] and [CTRL] for the right hand. It should bring up a dialog. Under "Effects" (the bottom-most options) for the left-hand menu choose "SC", which is "note cut". Then use the related slider to choose a value of "1" from zero to 5. The "SC1" should appear on the pattern where you put the edit cursor.
* to change the tempo the effect letter is "T", and then a hexadecimal value which is from &H20 to &HFF. For 120BPM use "T78". Or visit the General tab.

Code: (Select All)
'by mnrvovrfc 16-Mar-2023, use for OpenMPT
'find the way to paste the patterns without getting bored!
$CONSOLE:ONLY
OPTION _EXPLICIT

DIM assn(1 TO 10) AS STRING
DIM assc(1 TO 10) AS INTEGER
DIM afile$, aline$, emptycell$, noat$, oldn$, ve$, sig$, closeit AS _BYTE
DIM AS INTEGER ss, seqlen, numlines, linespat, acch
DIM AS LONG ff, u, v, h, i, j

'initialize
afile$ = "omptchblende.txt"
IF NOT _FILEEXISTS(afile$) THEN
    PRINT "File not found. This is needed to run the program."
    SYSTEM
END IF

emptycell$ = "|" + STRING$(11, 46)
'the clipboard data must have the following as first line.
'the "MPT" means "MPTM" or "(Open) ModPlug Tracker Module" which is a "dirtied" version of Impulse Tracker module which has
'  support for additional pattern commands and instrument microtuning.
'could instead be "IT" (Impulse Tracker), "XM" (FastTracker II), EITHER MUST HAVE AN ADDITIONAL SPACE AT FRONT
'  or it could be "MOD" mostly for ancient Amiga Protracker 4-channel right-left-left-right format.
'however "IT" format cannot have "S9F", cannot have "#" parameter extension command and a few other things on pattern
'  supported instead by "MPTM" format. Generally for new songs with VST plug-ins it's strongly recommended to do it in "MPTM" format.
'  They tend to have better sound quality,
'  while "IT" and "XM" are better for compatibility with players of those ancient formats, widely available.
'Scream Tracker "S3M" is sort of subset of "IT" which cannot have instruments, only samples and OPL synth assignments.
'"XM" actually supersedes "MOD" but there are so many "MOD" files around Internet which could be loaded by Commodore Amiga program.
'However, such things exist like 8-channel MOD created from a Windows program (don't remember what it was called).
'LOL sorry for the history, only wanted to demonstrate OpenMPT is friendly about pattern clipboard format.
sig$ = "ModPlug Tracker MPT"

seqlen = -1
numlines = -1
linespat = -1
acch = -1

'process the response file
ff = FREEFILE
OPEN afile$ FOR INPUT AS ff
DO UNTIL EOF(ff)
    LINE INPUT #ff, aline$
    IF aline$ <> "" THEN
        u = INSTR(aline$, ";")
        IF u > 0 THEN
            ss = ss + 1
            IF ss <= 10 THEN
                assn(ss) = aline$
                assc(ss) = CountString(aline$, ";")
            END IF
        ELSE
            u = VAL(aline$)
            IF u > 0 THEN
                IF seqlen = -1 THEN
                    'what is the total length of the sequence we have to create?
                    seqlen = u
                ELSEIF numlines = -1 THEN
                    'what is the length of the sequence (which could be repeated)?
                    numlines = u
                ELSEIF linespat = -1 THEN
                    'how many rows per pattern?
                    linespat = u
                ELSEIF acch = -1 THEN
                    'what is the chance (1 to 10) to accent notes?
                    acch = u
                END IF
            END IF
        END IF
    END IF
LOOP
CLOSE ff

'check the parameters for sanity
IF linespat < 16 OR linespat > 1024 THEN
    PRINT "Preference processing error."
    PRINT "linespat is not valid, must be from 16 to 1024."
    SYSTEM
END IF
IF seqlen < linespat THEN
    PRINT "Please change the value of seqlen in the preference file."
    SYSTEM
END IF
IF acch < 1 OR acch > 10 THEN
    PRINT "Preference processing error."
    PRINT "acch must be from 1 to 10."
    SYSTEM
END IF

RANDOMIZE TIMER

REDIM sq(1 TO seqlen) AS STRING
REDIM sf(1 TO numlines) AS STRING

'create the original sequence (like an ancient piano roll, it could be repeated)
oldn$ = ""
FOR j = 1 TO numlines
    DO
        v = Random1(10)
    LOOP WHILE assc(v) = 0
    h = assc(v)
    DO
        u = Random1(h)
        noat$ = SSelect$(assn(v), u)
    LOOP WHILE noat$ = ""
    IF oldn$ = noat$ THEN
        sf(j) = ""
    ELSE
        oldn$ = noat$
        sf(j) = "|" + noat$ + "01"
    END IF
NEXT

'now create the entire sequence, which will repeat but the accents will be in different places!
j = 1
FOR i = 1 TO seqlen
    IF sf(j) = "" THEN
        sq(i) = emptycell$
    ELSE
        sq(i) = sf(j)
        IF Random1(10) > acch THEN ve$ = "..." ELSE ve$ = "v32"
        IF j = numlines THEN
            IF ve$ = "..." THEN ve$ = "==="
        END IF
        sq(i) = sq(i) + ve$ + "..."
    END IF
    j = j + 1
    IF j > numlines THEN j = 1
NEXT
ERASE sf

'finally commit the patterns to disk
'later on LOL laboriously paste them into OpenMPT
'it was much easier on Windows using AutoHotKey...
v = 1
j = 1
$IF WIN THEN
        afile$ = ENVIRON$("USERPROFILE") + "\Documents\pat" + Zeroes$(j, 3) + ".txt"
$ELSE
        afile$ = ENVIRON$("HOME") + "/Documents/pat" + Zeroes$(j, 3) + ".txt"
$END IF
ff = FREEFILE
OPEN afile$ FOR OUTPUT AS ff
PRINT #ff, sig$
FOR i = 1 TO seqlen
    PRINT #ff, sq(i)
    v = v + 1
    IF v > linespat THEN
        PRINT afile$
        v = 1
        j = j + 1
$IF WIN THEN
        afile$ = ENVIRON$("USERPROFILE") + "\Documents\pat" + Zeroes$(j, 3) + ".txt"
$ELSE
        afile$ = ENVIRON$("HOME") + "/Documents/pat" + Zeroes$(j, 3) + ".txt"
$END IF
        CLOSE ff
        IF i = seqlen THEN
            closeit = 0
        ELSE
            closeit = 1
            ff = FREEFILE
            OPEN afile$ FOR OUTPUT AS ff
            PRINT #ff, sig$
        END IF
    END IF
NEXT
IF closeit THEN
    PRINT afile$
    CLOSE ff
END IF
PRINT j; "files written to disk. Completed."
SYSTEM


FUNCTION CountString% (tx$, delim$)
    DIM AS LONG lx, z1, z2
    DIM count AS INTEGER
    IF (tx$ = "") OR (delim$ = "") THEN
        CountString% = 0
        EXIT FUNCTION
    END IF
    lx = LEN(delim$)
    z1 = 1
    z2 = INSTR(tx$, delim$)
    count = 0
    DO UNTIL z2 = 0
        count = count + 1
        z1 = z2 + lx
        z2 = INSTR(z1, tx$, delim$)
    LOOP
    CountString% = count
END FUNCTION

'note: "delim$" could be a string of any size, preferably as short as possible
FUNCTION FieldString$ (tx$, ndx%, delim$)
    DIM AS LONG lx, y, z1, z2
    DIM count AS INTEGER
    IF (tx$ = "") OR (delim$ = "") OR (ndx% < 1) THEN
        FieldString$ = ""
    ELSE
        count = CountString(tx$, delim$) + 1
        IF ndx% > count THEN
            FieldString$ = ""
            EXIT FUNCTION
        END IF
        lx = LEN(delim$)
        z1 = 1
        z2 = INSTR(tx$, delim$)
        y = 0
        DO UNTIL z2 = 0
            y = y + 1
            IF y >= ndx% THEN EXIT DO
            z1 = z2 + lx
            z2 = INSTR(z1, tx$, delim$)
        LOOP
        IF (z2 = 0) AND (y <= ndx%) THEN
            FieldString$ = MID$(tx$, z1)
        ELSE
            FieldString$ = MID$(tx$, z1, z2 - z1)
        END IF
    END IF
END FUNCTION

FUNCTION LeftLen$ (tx$, numchar%)
    IF tx$ = "" THEN
        LeftLen$ = ""
    ELSEIF numchar% > 0 THEN
        LeftLen$ = LEFT$(tx$, LEN(tx$) - numchar%)
    ELSE
        LeftLen$ = tx$
    END IF
END FUNCTION

FUNCTION Random1& (maxval AS LONG)
    Random1 = INT(RND * maxval + 1)
END FUNCTION

FUNCTION SSelect$ (tx$, valu%)
    SSelect$ = FieldString$(tx$, valu%, ";")
END FUNCTION

FUNCTION Zeroes$ (num AS LONG, numdig AS INTEGER)
    DIM b$, sg AS _BYTE, hx AS _BYTE, v AS INTEGER
    IF num < 0 THEN sg = -1: num = num * -1
    IF numdig < 0 THEN hx = 1: numdig = numdig * -1 ELSE hx = 0
    IF hx THEN
        b$ = HEX$(num)
    ELSE
        b$ = LTRIM$(STR$(num))
    END IF
    v = numdig - LEN(b$)
    IF v > 0 THEN b$ = STRING$(v, 48) + b$
    IF sg = -1 THEN b$ = "-" + b$
    Zeroes$ = b$
END FUNCTION