' Program Name : MKJNOTES.BAS
' Description  : Takes a MKJ song and generates the string of notes
'                into the given file name.  Almost like a MKJ
'                "de-compiler"
'
' Written in 1996 by Molnar \ Kucalaba Productions

DECLARE FUNCTION LoadJamFile% (File$)
DECLARE FUNCTION ChannelNotes$ (Channel%)

'$DYNAMIC  ' We have to resize the Song Buffer when loading


DIM SHARED MaxChannel%, MaxNotes%

CONST MaxPlay% = -1

' Instrument-type.  For your convenience, use the MKJamz Instrument Creator.
' After all, that's what it's there for.
TYPE InsType
 MMult AS INTEGER     ' Modulator's Multiple
 MLevel AS INTEGER    ' Modulator's Level
 MAttack AS INTEGER   ' Modulator's Attack
 MSustain AS INTEGER  ' Modulator's Sustain
 CMult AS INTEGER     ' Carrier's Multiple
 CLevel AS INTEGER    ' Carrier's Level
 CAttack AS INTEGER   ' Carrier's Attack
 CSustain AS INTEGER  ' Carrier's Sustain
END TYPE


' This template holds the current channel information.
TYPE ChannelType
 Defined AS INTEGER   ' Has the user defined the channel and it's notes? (1 if yes)
 Speed AS SINGLE      ' The duration of each note
 SongPtr AS INTEGER   ' A pointer to the current song position
 PStat AS SINGLE      ' Pause counter 2
 Octave AS INTEGER    ' The Octave of each channel
 WaveForm AS INTEGER  ' The Wave Form of each channel
 Flag AS INTEGER      ' Misc control flag
 Flag2 AS INTEGER     ' Number of times to play song
 IsPlaying AS INTEGER ' Is a note playing (1=yes)
 IsDone AS INTEGER    ' Has the note stopped? (1=yes)
END TYPE



DIM SHARED ChannelStat(1 TO 2) AS ChannelType ' We will resize this when
                                              ' loading a MK Jamz file.

DIM SHARED SongBuf(1 TO 2) AS INTEGER ' We will resize this when loading
                                      ' a MK Jamz file.

DIM SHARED CurrentIns AS InsType ' We use this buffer for loading and setting FM
                                 ' instrument types.


CLS

COLOR 15
PRINT
PRINT "                               .MKJ Note Generator"
PRINT
COLOR 14
PRINT "             Please type in the .MKJ file to generate notes from."
PRINT
COLOR 15
INPUT "File Name : ", FileName$
COLOR 14
PRINT
ReturnCode% = LoadJamFile(FileName$)

  SELECT CASE ReturnCode%
    CASE IS <> 1: PRINT "Error reading original .MKJ file, code : "; ReturnCode%
                  WHILE INKEY$ = "": WEND
                  SYSTEM
  END SELECT

PRINT "   Song successfully loaded, please type in the note file to be created."
PRINT
COLOR 15
INPUT "Note File : ", OutFile$
PRINT
OPEN OutFile$ FOR OUTPUT AS #1
FOR x% = 1 TO MaxChannel%
 PRINT #1, "Channel" + LTRIM$(RTRIM$(STR$(x%))) + "$ = " + CHR$(34); ChannelNotes(x%) + CHR$(34)
NEXT
CLOSE #1
PRINT
COLOR 14
PRINT "                     Notes generated, have a nice day."
DO: LOOP UNTIL INKEY$ <> ""
SYSTEM

REM $STATIC
FUNCTION ChannelNotes$ (Channel%)
Temp$ = ""

FOR x% = Channel% TO (MaxNotes% * MaxChannel%) STEP MaxChannel%
 SELECT CASE SongBuf(x%)
   CASE 67: Temp$ = Temp$ + "c"
   CASE 68: Temp$ = Temp$ + "d"
   CASE 69: Temp$ = Temp$ + "e"
   CASE 70: Temp$ = Temp$ + "f"
   CASE 71: Temp$ = Temp$ + "g"
   CASE 65: Temp$ = Temp$ + "a"
   CASE 66: Temp$ = Temp$ + "b"
   CASE 17: Temp$ = Temp$ + "c#"
   CASE 18: Temp$ = Temp$ + "d#"
   CASE 20: Temp$ = Temp$ + "f#"
   CASE 21: Temp$ = Temp$ + "g#"
   CASE 15: Temp$ = Temp$ + "a#"
   CASE 253: Temp$ = Temp$ + "t(" + LTRIM$(RTRIM$(STR$(SongBuf(x% + MaxChannel%) / 100))) + ")": x% = x% + MaxChannel%
   CASE 255: Temp$ = Temp$ + "p(" + LTRIM$(RTRIM$(STR$(SongBuf(x% + MaxChannel%) / 100))) + ")": x% = x% + MaxChannel%
   CASE 254: Temp$ = Temp$ + "o" + LTRIM$(RTRIM$(STR$(SongBuf(x% + MaxChannel%)))): x% = x% + MaxChannel%
   CASE 252: Temp$ = Temp$ + "w(" + LTRIM$(RTRIM$(STR$(SongBuf(x% + MaxChannel%)))) + ")": x% = x% + MaxChannel%
   CASE 251: Temp$ = Temp$ + "x"

  END SELECT
NEXT

ChannelNotes$ = Temp$



END FUNCTION

FUNCTION LoadJamFile% (File$)

OPEN File$ FOR BINARY AS #1

 IF LOF(1) < 2 THEN
  CLOSE #1
  KILL File$
  LoadJamFile% = -1
  EXIT FUNCTION
 END IF

 IF INPUT$(6, #1) <> "MKJamz" THEN
   LoadJamFile% = -2
   EXIT FUNCTION
 END IF

 GET #1, , Version!
 IF Version! > 1.1 THEN
  LoadJamFile% = -3
  EXIT FUNCTION
 END IF

 GET #1, , MaxChannel%

  FOR x% = 1 TO MaxChannel%
    GET #1, , CurrentIns
  NEXT

 GET #1, , MaxNotes%

  REDIM SongBuf(1 TO (MaxChannel% + 1) * MaxNotes%) AS INTEGER
  REDIM ChannelStat(1 TO MaxChannel%) AS ChannelType

  FOR x% = 1 TO MaxChannel%
    GET #1, , ChannelStat(x%).Defined
    ChannelStat(x%).SongPtr = 1
    ChannelStat(x%).Octave = 4
  NEXT


  ' Begin of FAST music loader...load 40,000 bytes of data in no time flat!
  ' Almost like BLOAD/BSAVE but much more flexible.  (If you know what you
  ' are doing.)


  RemBytes& = LOF(1) - SEEK(1)  ' The size, in bytes (not ints) of song data

  BufferSize% = 2000           ' The buffer size to use.

  DEF SEG = VARSEG(SongBuf(1)) ' The segment of the song buffer
  Ptr& = VARPTR(SongBuf(1))    ' Pointer to the song buffer

  LeftBytes& = RemBytes& MOD BufferSize% ' The amount of left over bytes

  IF (LeftBytes& < RemBytes&) THEN
    FOR QuickLoad% = 1 TO (RemBytes& - LeftBytes&) / BufferSize%
       Buffer$ = INPUT$(BufferSize%, #1) ' Load all the data into buffer
         FOR x% = 1 TO LEN(Buffer$)
            POKE Ptr&, ASC(MID$(Buffer$, x%, 1))
            Ptr& = Ptr& + 1
         NEXT
       RemBytes& = RemBytes& - BufferSize%
    NEXT
  END IF

  IF (LeftBytes& > 0) THEN
    Buffer$ = INPUT$(LeftBytes&, #1)
     FOR x% = 1 TO LEN(Buffer$)
        POKE Ptr&, ASC(MID$(Buffer$, x%, 1))
        Ptr& = Ptr& + 1
     NEXT
   END IF

  DEF SEG

CLOSE #1

LoadJamFile% = 1

END FUNCTION

