#INCLUDE "fbmath.bi" #MACRO WriteNote(a) IF ctype(i) = 0 THEN curfreq(i) = fmfreq(a) PUT #20, , chr(esfchan(i) + &h30) PUT #20, , chr(INT(curfreq(i) / 256)) PUT #20, , chr(INT(curfreq(i) MOD 256)) else curfreq(i) = INT((0.5^((a)/12-1))/2*851) if ctype(i) = 3 and noisetype = 0 then PUT #20, , chr(&h3A) else PUT #20, , chr(esfchan(i) + &h30) PUT #20, , chr(INT(curfreq(i) MOD 16)) + chr(INT(curfreq(i) / 16)) end if #ENDMACRO #MACRO WriteCurrentFreq() IF ctype(i) = 0 THEN PUT #20, , chr(esfchan(i) + &h30) PUT #20, , chr(INT(curfreq(i) / 256)) PUT #20, , chr(INT(curfreq(i) MOD 256)) ELSE if ctype(i) = 3 and noisetype = 0 then PUT #20, , chr(&h3A) else PUT #20, , chr(esfchan(i) + &h30) PUT #20, , chr(INT(curfreq(i) MOD 16)) + chr(INT(curfreq(i) / 16)) END IF #ENDMACRO TYPE PATTERNDATA note AS STRING * 1 INST AS STRING * 1 VC AS STRING * 1 ET AS STRING * 1 EP AS STRING * 1 END TYPE FUNCTION SPLEFT(strn as string) AS STRING dim i as long dim car as string dim cars as string dim comp as string dim speft as string i = 1 car = MID(strn, 1, 1) IF car = chr(34) THEN comp = chr(34) i = 2 car = MID(strn, 2, 1) ELSE comp = " " END IF WHILE car <> comp SPEFT = SPEFT + car i = i + 1 car = MID(strn, i, 1) IF i > LEN(strn) THEN SPLEFT = SPEFT + cars EXIT FUNCTION END IF WEND SPLEFT = SPEFT END FUNCTION FUNCTION param(strn as string, b as long) AS STRING dim i as long dim c as long dim car as string dim cars as string dim comp as string dim speft as string c = 0 i = 1 car = MID(strn, 1, 1) IF car = chr(34) THEN comp = chr(34) i = 2 car = MID(strn, 2, 1) ELSE comp = " " END IF WHILE c <> b WHILE car <> comp SPEFT = SPEFT + car i = i + 1 car = MID(strn, i, 1) IF i > LEN(strn) THEN SPEFT = "" param = SPEFT EXIT FUNCTION END IF WEND i = i + 1 c = c + 1 ' SPEFT$ = MID(strn, i&, 1) car = SPEFT WEND param = RTRIM(spleft(MID(strn,i))) END FUNCTION FUNCTION DIVREST(a as double, b as integer) as DOUBLE dim last as integer dim i as integer last = 0 for i = 0 to a step 1 if i / b - int(i / b) = 0 and i <= a then last = i end if next i divrest = a - last END FUNCTION FUNCTION fmfreq(a AS double) AS INTEGER dim temp2 as long dim temp as long temp2 = INT(644*(2^(divrest(a,12)/12))) temp = ((INT(a/12)) * 2048) temp2 = INT((temp2 AND 2047) + temp) return temp2 END FUNCTION FUNCTION fmfreq2(a AS integer) AS INTEGER fmfreq2 = fmfreq(cast(double,a)) END FUNCTION FUNCTION fmvol(a AS DOUBLE) AS BYTE DIM b AS INTEGER b = &H7F - int(log10(a * 9.0 / 64 + 1.0) * &H7F + 0.5) print "FMVOL : ";b IF b > 127 THEN b = 127 IF b < 0 THEN b = 0 IF a = 64 THEN b = 0 IF a = 0 THEN b = 127 fmvol= b END FUNCTION FUNCTION fmvol2(a AS INTEGER) AS BYTE DIM b AS INTEGER b = &H7F - int(log10(a * 9.0 / 64 + 1.0) * &H7F + 0.5) print "FMVOL : ";b IF b > 127 THEN b = 127 IF b < 0 THEN b = 0 IF a = 64 THEN b = 0 IF a = 0 THEN b= 127 fmvol2= b END FUNCTION FUNCTION psgvol(a AS DOUBLE) AS BYTE DIM b AS INTEGER b = -(INT(LOG10(a / 64.0) * 7)) IF b > 15 THEN b = 15 IF a = 64 THEN b = 0 IF a = 0 THEN b = 15 psgvol= b END FUNCTION FUNCTION psgvol2(a AS INTEGER) AS BYTE DIM b AS INTEGER b = -(INT(LOG10(a / 64.0) * 7)) IF b > 15 THEN b = 15 IF a = 64 THEN b = 0 IF a = 0 THEN b = 15 psgvol2 = b END FUNCTION '************************************ '* XM2ESF * '************************************ ' ' Converts XM-format module music to ' Echo Stream Format ' ' VERSION: dim builddate as string dim version as string builddate = "10-20-2012" version = "1.00 RC6" #IFDEF __FB_DOS__ version = version + " DOS" #Endif #IFDEF __FB_WIN32__ version = version + " Win32" #Endif #IFDEF __FB_Linux__ version = version + " Linux" #Endif ' ' (C) 2009, 2010, 2011, 2012 Oerg866 ' ' Developed in compliance with official Echo docs. (C) 2010, 2011, 2012 Sik ' RMDIR "./TEMP" MKDIR "./TEMP" PRINT "XM2ESF - XM to Echo Stream Format converter" PRINT "" PRINT "Version " + version + " " + builddate PRINT "" PRINT "Copyright (C) 2011-2012 Oerg866 http://www.mdscene.net" PRINT " http://github.com/oerg866/xm2esf" PRINT "" PRINT "Echo (C) 2010-2012 Sik http://echo.mdscene.net" PRINT "" PRINT "Please report bugs using email at oerg866@tototek.com or use any" PRINT "other viable method, such as forum threads, etc." PRINT "" PRINT "This program is free. It must not be sold. This is a temporary" PRINT "disclaimer until a proper license is in place." PRINT "" COLOR 14,0 PRINT "Please acknowledge that this program is not in a stable state yet" PRINT "and its creator can not be held responsible for consequences" PRINT "evolving from the usage, be it proper or improper, of this" PRINT "program." COLOR 7,0 PRINT "" PRINT "Also, lots of hours of bugfixing and testing went into this." PRINT "Please keep this in mind when using this program." PRINT "" PRINT "" PRINT "" SLEEP 1000 IF COMMAND$ = "" THEN PRINT "usage: xm2esf -" PRINT "" PRINT " is an XIF file. An XIF file is a descriptor" PRINT " file that contains all the parameters which xm2esf will" PRINT " respect while creating the resulting ESF file, and also the" PRINT " path and filename to the input XM file." PRINT "" PRINT " Creating an XIF file is possible using the bundled xm2esfgui" PRINT " It is very easy to use and creates a XIF file" PRINT " that is perfectly parseable by xm2esf :)" PRINT "" PRINT " For other software and information, please visit" PRINT " http://segaretro.org/Echo" PRINT "" PRINT " is the output path ad filename xm2esf will use to create" PRINT " the resulting ESF file. Please note that if this file exists" PRINT " it WILL BE OVERWRITTEN, even if you encounter a bug and the" PRINT " conversion somehow fails ." PRINT "" print "Switches:" print "" print "-r" print "" print "-p" PRINT "" PRINT "Bye :D!" END END IF dim cmdl as integer dim psgretrig as byte dim psgretrigall as byte dim psgignore as byte for cmdl = 3 to 255 if command$(cmdl) = "" then exit for select case lcase(command$(cmdl)) case "-r" psgretrigall = 1 case "-p" psgretrig = 1 case "-i" psgignore = 1 end select next cmdl print "psgretrigall ";psgretrigall print "psgretrig ";psgretrig print "psgignore ";psgignore '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' INITIALIZE ALL VARIABLES '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' '' XM to ESF channel assignment variables DIM xmfm(1 TO 6) as long ' Contains the corresponding XM channel for each PSG channel DIM xmpsg(1 TO 3) as long ' Contains the corresponding XM channel for each PSG channel dim xmnoise as long dim xmpcm as long DIM fm as long ' Amount of FM channels DIM psg as long ' Amount of PSG channels dim pcm as long DIM present(1 TO 11) as long ' Used to define if a channel is present '' XM to ESF Instrument assignment variables DIM esfins(1 TO 256) as long ' Contains the corresponding Echo Instrument ID (in Pointer List) ' for each XM instrument '' XM to ESF Song adjustment variables DIM pitch(1 TO 11) as long ' Transpose value for each channel DIM vol(1 TO 11) as long ' Channel volume for every channel DIM quotient(1 TO 11) AS DOUBLE ' Volume conversion quotient '' XM to ESF Conversion loop and temporary variables: dim xmnote as long dim xmvol as long dim xmeff as long dim xmeffdat as long DIM i AS INTEGER ' For some loops DIM currow AS LONG ' Current row of entire song that's being processed '' XM to ESF stream data bridge variables DIM row(1 TO 11) as string ' Current XM row for each channel DIM curins(1 TO 11) as long ' Current XM instrument DIM curnote(1 TO 11) as long ' Current note (XM note with transpose already applied !) DIM curvol(1 TO 11) as long ' Current volume DIM curfreq(1 TO 9) as long ' Current frequency (Used when writing new freq during portamento, vibrato and arpeggio) DIM effectdat(1 TO 11) as long ' Current Effect number DIM effectval(1 TO 11) as long ' Current Effect value DIM xmins as long ' Instrument column in current XM row DIM slidestep(1 TO 11) AS DOUBLE ' Current step during a slide (effects 1,2 and 3) Unit: XM notes DIM slidetarget(1 TO 11) as long ' Target for a slide (effects 1,2, and 3) Unit: XM Notes DIM slidespeed(1 TO 11) as long ' Amount of XM notes to slide per tick DIM volslidepos(1 TO 11) AS DOUBLE ' Current position in volume slide (effect A), unit: XM volume DIM volslidespeed(1 TO 11) AS DOUBLE' Amount of volume to slide per tick DIM arpnote1(1 TO 11) as long ' Note 1 in arpeggio (effect 0) DIM arpnote2(1 TO 11) as long ' Note 2 in arpeggio (effect 0) DIM vibstep(1 TO 11) AS DOUBLE ' Current step in a vibrato (note this is NOT in XM notes! ' It's just the amouont of ticks that already have been ' processed in a vibrato! it starts at 0, so that a smooth ' sinewave can be applied, that starts at the current note!) DIM vibspeed(1 TO 11) as long ' Vibrato speed (1st parameter in effect 4) DIM vibdepth(1 TO 11) as long ' Vibrato depth (2nd parameter in effect 4) DIM conversion AS DOUBLE ' note to frequency conversion variable '' XM to ESF Conversion initalization variables DIM esfchan(1 TO 11) as long ' This is pretty interesting. ' (and VERY important I might add) esfchan(1) = 0 ' The echo stream format definitions use direct YM2612/PSG esfchan(2) = 1 ' channel values. These are not 0-10 or something like that esfchan(3) = 2 ' but have gaps in them due to the way the chip is constructed. esfchan(4) = 4 ' This bridge variable takes care of this. esfchan(5) = 5 esfchan(6) = 6 esfchan(7) = 8 esfchan(8) = 9 esfchan(9) = 10 esfchan(10) = 12 esfchan(11) = 11 DIM fmnote(0 TO 11) as long ' Pre-defined FM frequencies for every note (source: echo table) fmnote(0) = 644 fmnote(1) = 681 fmnote(2) = 722 fmnote(3) = 765 fmnote(4) = 810 fmnote(5) = 858 fmnote(6) = 910 fmnote(7) = 964 fmnote(8) = 1024 fmnote(9) = 1081 fmnote(10) = 1146 fmnote(11) = 1214 DIM psgnote(0 TO 70) as long ' Pre-defined PSG frequencies for every note (source: echo table) DIM ctype(1 TO 11) AS INTEGER ' Channel type (defines internally which channels from 1 to 11 are FM, PSG, PCM and Noise DIM loopins(1 TO 11) as long ' Variables for (re)storing instruments on looping DIM lastfx(1 TO 11) as long ' Variables for picking up pitch related effects DIM lastfd(1 TO 11) as long ' Variables for picking up pitch related effects '''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' INIT CODE BEGINS HERE :) ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' ' Please note: If the XM's Tempo is set to 150, every tick is exactly the same length as one echo tick ' Meaning that the adjustable variable is the "Ticks per row". If XM's tempo is 150, you should set ' the ticks per row value as the speed in the XIF input file. If you do that, your XM will be ' exactly as fast as the echo output!! ' most tempo values other than 150 will mean that the actual esf's speed will only be able to approximate ' the actual XM speed. dim tempo as long tempo = 7 ' Default is 7. A tempo of 150;7 is almost the same as the default many trackers use (125;6) KILL COMMAND$(2) OPEN COMMAND$(1) FOR INPUT AS #1 ' This is the XIF file parser. It is long, andthe coding style is probably pretty bad. But! it works :P ' The error handler is not very intelligent yet. But, it'll be, sooner or later. Probably later =P dim setting as string dim esfloop as long dim filetype as long dim xm as string dim noise as long dim noisetype as long dim noisemode as long dim restart as long dim total as long dim temp as long dim tmp as long dim pf as long WHILE LCASE(setting) <> "[instruments]" LINE INPUT #1, setting IF MID(setting, 1, 1) <> "#" THEN SELECT CASE spleft(setting) CASE "FILE" xm = param(setting, 1) PRINT "XM File: " + xm CASE "TYPE" SELECT CASE param(setting, 1) CASE "BGM" filetype = 1 CASE "SFX" filetype = 2 END SELECT SELECT CASE param(setting, 2) CASE "LOOP" esfloop = 1 IF filetype = 2 THEN PRINT "Input file errorneously declares loop while being a SFX. File rejected." CLOSE END END IF CASE "NOLOOP" esfloop = 0 END SELECT CASE "TEMPO" tempo = VAL(param(setting, 1)) CASE "FM" fm = VAL(param(setting, 1)) IF fm > 6 THEN PRINT "Declared more than 6 FM channels." CLOSE:END END IF CASE "PSG" psg = VAL(param(setting, 1)) IF psg > 3 THEN PRINT "Declared more than 3 PSG channels." CLOSE END END IF CASE "PCM" pcm = 1 IF fm = 6 THEN PRINT "Input file errorneously declares PCM even though 6 FM channels are used" CLOSE END END IF CASE "NOISE" noise = VAL(param(setting, 1)) CASE "FM1" xmfm(1) = VAL(param(setting, 1)) CASE "FM2" xmfm(2) = VAL(param(setting, 1)) CASE "FM3" xmfm(3) = VAL(param(setting, 1)) CASE "FM4" xmfm(4) = VAL(param(setting, 1)) CASE "FM5" xmfm(5) = VAL(param(setting, 1)) CASE "FM6" xmfm(6) = VAL(param(setting, 1)) CASE "PCMC" xmpcm = VAL(param(setting,1)) CASE "PSG1" xmpsg(1) = VAL(param(setting, 1)) CASE "PSG2" xmpsg(2) = VAL(param(setting, 1)) CASE "PSG3" xmpsg(3) = VAL(param(setting, 1)) CASE "PSGN" xmnoise = VAL(param(setting, 1)) CASE "NOISEFREQ" ' 1 = stock, 0 = psg3 noisetype = VAL(param(setting, 1)) CASE "NOISETYPE" noisemode = VAL(param(setting, 1)) '1 = white noise, 0 = periodic noise END SELECT END IF WEND '''''''''''''''''''''''''''''''''''''''''''''''''''' '' This calls a small program called LOADXM. '' It is a win32 self-contain port of nineko's '' original XM loader (QB/VB6). Ported and used '' with permission. Thanks, nineko! '''''''''''''''''''''''''''''''''''''''''''''''''''' dim s as string PRINT "loading XM file: " + xm #IfDEF __FB_DOS__ s = "loadxm " + xm #Endif #IfDEF __FB_WIN32__ s = "loadxm " + chr(34) + xm + chr(34) #Endif #IfDEF __FB_Linux__ s = "loadxm " + xm #Endif print "Executing " + s SHELL s '' TODO: ERRORLEVEL checking. Because I was lazy and did not '' bother to check if loadxm actually was successful, '' xm2esf will still be let lose if loadxm failed. '' Oh well ^__^" PRINT "XM pattern data extracted" '''''''''''''''''''''''''''''''''''''''''''''''''''' 'INSTRUMENT ASSIGNMENTS WHILE LCASE(setting) <> "[pitch]" IF MID(setting,1,1) <> "#" THEN LINE INPUT #1, setting esfins(VAL(spleft(setting))) = VAL("&H" + param(setting,1)) ELSE LINE INPUT #1, setting END IF WEND PRINT "Loaded pitches" ' Internal channel to variable assignment help ' 123456 = FM ' 789 = PSG ' 11 = PCM ' 10 = NSE WHILE LCASE(setting) <> "[volume]" LINE INPUT #1, setting IF MID(setting,1,1) <> "#" THEN SELECT CASE spleft(setting) CASE "FM1" pitch(1) = VAL(param(setting,1)) CASE "FM2" pitch(2) = VAL(param(setting,1)) CASE "FM3" pitch(3) = VAL(param(setting,1)) CASE "FM4" pitch(4) = VAL(param(setting,1)) CASE "FM5" pitch(5) = VAL(param(setting,1)) CASE "FM6" pitch(6) = VAL(param(setting,1)) CASE "PSG1" pitch(7) = VAL(param(setting,1)) CASE "PSG2" pitch(8) = VAL(param(setting,1)) CASE "PSG3" pitch(9) = VAL(param(setting,1)) CASE "PSGN" pitch(11) = VAL(param(setting,1)) END SELECT END IF WEND WHILE LCASE(setting) <> "[end]" LINE INPUT #1, setting IF MID(setting,1,1) <> "#" THEN SELECT CASE spleft(setting) CASE "FM1" vol(1) = VAL(param(setting,1)) CASE "FM2" vol(2) = VAL(param(setting,1)) CASE "FM3" vol(3) = VAL(param(setting,1)) CASE "FM4" vol(4) = VAL(param(setting,1)) CASE "FM5" vol(5) = VAL(param(setting,1)) CASE "FM6" vol(6) = VAL(param(setting,1)) CASE "PSG1" vol(7) = VAL(param(setting,1)) CASE "PSG2" vol(8) = VAL(param(setting,1)) CASE "PSG3" vol(9) = VAL(param(setting,1)) CASE "PSGN" vol(11) = VAL(param(setting,1)) END SELECT END IF WEND ' CLOSE OPEN COMMAND(2) FOR BINARY AS #20 FOR i = 1 TO fm present(i) = 1 OPEN "TEMP\C" + TRIM(STR(xmfm(i))) + ".tmp" FOR BINARY AS #i NEXT i FOR i = 7 TO psg + 6 present(i) = 1 OPEN "TEMP\C" + TRIM(STR(xmpsg(i-6))) + ".tmp" FOR BINARY AS #i NEXT i IF pcm = 1 THEN present(10) = 1 OPEN "TEMP\C" + TRIM(STR(xmpcm)) + ".tmp" FOR BINARY AS #10 END IF IF noise = 1 THEN present(11) = 1 OPEN "TEMP\C" + TRIM(STR(xmnoise)) + ".tmp" FOR BINARY AS #11 END IF PRINT "Channels assigned and loaded" ''''''''''''''''''''''''''''''''''''''''' '' LOAD ALL PREDEFINED PSG FREQUENCIES '' ''''''''''''''''''''''''''''''''''''''''' dim t as long t=0 FOR t = 0 TO 70 READ psgnote(t) NEXT t PRINT "PSG Freq init." ' Define channel types ' 0 = FM (default) ' 1 = PSG ' 2 = PCM ' 3 = Noise ctype(7) = 1 ctype(8) = 1 ctype(9) = 1 ctype(10) = 2 'pcm ctype(11) = 3 'noise dim a as string i = FREEFILE OPEN "TEMP\file.inf" FOR INPUT AS #i LINE INPUT #i, a LINE INPUT #i, a: restart = VAL(a) LINE INPUT #i, a: total = VAL(a) CLOSE #i PRINT "File info read..." FOR i = 1 TO 11 row(i) = " " effectdat(i) = 255 effectval(i) = 255 NEXT i FOR i = 1 TO 11 quotient(i) = vol(i) / 64 NEXT i IF filetype = 2 THEN FOR i = 1 TO 11 IF present(i) = 1 THEN IF i = 11 THEN PUT #20,, chr(&hE6) ELSE PUT #20,, chr(&hE0 + esfchan(i)) END IF END IF NEXT i END IF PRINT "Starting conversion." FOR currow = 1 TO total IF currow-1 = restart THEN IF esfloop = 1 THEN PUT #20,, chr(&hFD) ' Store instruments for looping FOR i = 1 TO 11 loopins(i) = curins(i) NEXT i END IF END IF FOR i = 1 TO 11 IF present(i) = 1 THEN GET #i, , row(i) xmnote= ASC(MID(row(i), 1, 1)) xmins = ASC(MID(row(i), 2, 1)) xmvol = ASC(MID(row(i), 3, 1)) xmeff = ASC(MID(row(i), 4, 1)) xmeffdat = ASC(MID(row(i), 5, 1)) ' XM Effects handled by xm2esf: ' 0xx Arpeggio ' 1xx Portamento up ' 2xx Portamento down ' 3xx Tone Portamento ' 4xx Vibrato ' 8xx Set Panning ' Axx Volume Slide ' Cxx Set volume ' Dxx Pattern break (Always interpreted as D00!) ' F0x Set speed IF effectdat(i) <> 255 THEN lastfx(i) = effectdat(i) lastfd(i) = effectval(i) END IF '''''''''''''''''''''''''''''''''''''''''''''''' Set Speed IF xmeff = &hF THEN TEMPo = xmeffdat END IF '''''''''''''''''''''''''''''''''''''''''''''''' Reset any slide attributes when no related effect is in use IF xmeff > 4 OR xmeff = 0 THEN slidestep(i) = 0 slidespeed(i) = 0 slidetarget(i) = 0 END IF '''''''''''''''''''''''''''''''''''''''''''''''' Reset conversion values for effects when no effect is in use IF xmeff = 0 AND xmeffdat = 0 THEN effectdat(i) = 255 effectval(i) = 255 END IF '''''''''''''''''''''''''''''''''''''''''''''''' Arpeggio IF xmeff = 0 AND xmeffdat <> 0 THEN effectdat(i) = 0 effectval(i) = xmeffdat arpnote1(i) = INT(xmeffdat / 16) arpnote2(i) = INT(xmeffdat MOD 16) slidestep(i) = curnote(i) END IF '''''''''''''''''''''''''''''''''''''''''''''''' Set Panning IF xmeff = 8 THEN 'Set Panning IF ctype(i) <> 0 AND ctype(i) <> 2 THEN PRINT "WARNING: Panning on PSG or Noise channel! Ignoring..." ELSE if ctype(i) = 2 then put #20, , chr(&hf6) else PUT #20, , chr(esfchan(i) + &hF0) IF xmeffdat = &h80 THEN PUT #20, , chr(&hC0) ELSEIF xmeffdat > &h80 THEN PUT #20, , chr(&h40) ELSE PUT #20, , chr(&h80) END IF END IF END IF '''''''''''''''''''''''''''''''''''''''''''''''' Vibrato IF xmeff = 4 THEN IF effectdat(i) = 4 THEN vibspeed(i) = INT(xmeffdat / 16) vibdepth(i) = INT(xmeffdat MOD 16) effectdat(i) = 4 effectval(i) = xmeffdat ELSE effectdat(i) = 4 effectval(i) = xmeffdat vibspeed(i) = INT(xmeffdat / 16) vibdepth(i) = INT(xmeffdat MOD 16) vibstep(i) = 0 END IF END IF '''''''''''''''''''''''''''''''''''''''''''''''' Tone Portamento IF xmeff = 3 THEN IF lastfx(i) > 4 THEN slidestep(i) = curnote(i) IF effectdat(i) = 3 THEN IF slidespeed(i) < 0 THEN slidespeed(i) = (-1) * xmeffdat ELSE slidespeed(I) = xmeffdat END IF END IF effectdat(i) = 3 effectval(i) = xmeffdat IF xmnote > 0 AND xmnote < 97 THEN IF slidestep(i) <> 0 THEN IF xmnote + pitch(i) < slidestep(i) THEN slidespeed(i) = (-1) * xmeffdat ELSE slidespeed(i) = xmeffdat ELSE IF xmnote + pitch(i) < curnote(i) THEN slidespeed(i) = (-1) * xmeffdat ELSE slidespeed(i) = xmeffdat slidestep(i) = curnote(i) END IF slidetarget(i) = xmnote + pitch(i) END IF END IF IF xmnote < 97 AND xmnote > 0 THEN curnote(i) = xmnote +pitch(i) '''''''''''''''''''''''''''''''''''''''''''''''' Portamento Up / Down IF xmeff = 1 OR xmeff = 2 THEN IF lastfx(i) > 4 THEN slidestep(i) = curnote(i) if xmnote > 0 and xmnote <> 97 then slidestep(i) = xmnote + pitch(i) effectdat(i) = xmeff effectval(i) = xmeffdat slidespeed(i) = -((xmeff-1)*2-1) *xmeffdat if xmeffdat = &HFF then print "initiating, speed:"; slidespeed(i); " step:"; slidestep(i) slidetarget(i) = -(xmeff-2) * 96 END IF '''''''''''''''''''''''''''''''''''''''''''''''' Set current note variable IF xmnote < 97 AND xmnote > 0 THEN curnote(i) = xmnote + pitch(i) '''''''''''''''''''''''''''''''''''''''''''''''' Handle a IF xmnote = 97 and ((ctype(i) = 0 or ctype(i) = 2) or ((ctype(i) = 1 or ctype(i) = 3) and psgignore <> 0)) THEN PUT #20, , chr(esfchan(i)+&h10) END IF '''''''''''''''''''''''''''''''''''''''''''''''' Handle a new note IF xmnote > 0 AND xmnote < 97 THEN IF ctype(i) <> 2 THEN IF xmeff <> 3 THEN IF curins(i) <> xmins AND xmins <> 0 THEN curins(i) = xmins PUT #20, , chr(&H40 + esfchan(i)) PUT #20, , chr(INT(esfins(curins(i)))) END IF IF (xmeff <> 3) AND (xmeff <> &hc) THEN curvol(i) = 64 PUT #20, , chr(esfchan(i) + &h20) IF ctype(i) = 0 THEN TEMP = INT(fmvol(quotient(i) * 64)) PUT #20, , chr(TEMP) ELSE TEMP = INT(psgvol(quotient(i) * 64)) PUT #20, , chr(TEMP) END IF volslidepos(i) = curvol(i) END IF IF ctype(i) = 0 THEN PUT #20, , chr(esfchan(i)) PUT #20, , chr(INT(32 * INT(curnote(i) / 12) + (2 * (curnote(i) MOD 12)) + 1)) curfreq(i) = fmfreq(curnote(i)) ELSEIF ctype(i) = 1 THEN PUT #20, , chr(esfchan(i)) PUT #20, , chr(INT(24 * INT(curnote(i) / 12) + (2 * (curnote(i) MOD 12)))) curfreq(i) = INT((0.5^((curnote(i))/12-1))/2*851) ELSE tmp = 0 IF noisetype = 1 THEN tmp = 3 PUT #20, , chr(&hB) IF noisemode = 0 THEN PUT #20, , chr(&h0) ELSE PUT #20, , chr(&h4) END IF ELSE tmp = 3 curfreq(i) = INT((0.5^((curnote(i))/12-1))/2*851) PUT #20, , chr(&h3A) PUT #20, , chr(INT(curfreq(i) MOD 16)) + chr(INT(curfreq(i) / 16)) PUT #20, , chr(&hB) IF noisemode = 0 THEN PUT #20, , chr(&h3) ELSE PUT #20, , chr(&h7) END IF END IF END IF END IF ELSEIF ctype(i) = 2 THEN curins(i) = xmins PUT #20, , chr(&hC) PUT #20, , chr(esfins(curins(i))) END IF END IF '''''''''''''''''''''''''''''''''''''''''''''''' if ((psgretrig = 1 and xmeff > 0 and xmeff < 5) or (psgretrigall = 1)) and xmins > 0 and (ctype(i) = 1) then'or ctype(i) = 3) then curins(i) = xmins print "RETRIGGER" PUT #20, , chr(&H40 + esfchan(i)) PUT #20, , chr(INT(esfins(curins(i)))) put #20, , chr(&H10 + esfchan(i)) put #20, , chr(esfchan(i)) put #20, , chr(0) WriteCurrentFreq() end if '''''''''''''''''''''''''''''''''''''''''''''''' Volume Slide IF xmeff = &HA THEN IF ctype(i) <> 2 THEN IF effectdat(i) <> &hA THEN effectdat(i) = &hA volslidepos(i) = curvol(i) END IF IF INT(xmeffdat / 16) = &hF AND INT(xmeffdat MOD 16) > 0 THEN PRINT "WARNING: Fine volume slide detected, ignoring" ELSEIF INT(xmeffdat MOD 16) = &hF AND INT(xmeffdat / 16) > 0 THEN PRINT "WARNING: Fine volume slide detected, ignoring" ELSE IF INT(xmeffdat MOD 16) > 0 THEN ' Volume slide DOWN volslidespeed(i) = -(INT(xmeffdat MOD 16)) effectval(i) = INT(xmeffdat MOD 16) ELSEIF INT(xmeffdat / 16) > 0 THEN volslidespeed(i) = INT(xmeffdat / 16) / 16 effectval(i) = INT(xmeffdat / 16) END IF END IF END IF END IF '''''''''''''''''''''''''''''''''''''''''''''''' Set Volume IF xmeff = &HC THEN IF ctype(i) = 0 THEN effectdat(i) = &HC effectval(i) = xmeffdat PUT #20, , chr(esfchan(i) + &H20) TEMP = INT(fmvol(xmeffdat * quotient(i))) PUT #20, , chr(TEMP) curvol(i) = xmeffdat ELSEIF ctype(i)=1 THEN effectdat(i)= &HC effectval(i) = xmeffdat PUT #20, , chr(esfchan(i) + &H20) TEMP = INT(psgvol(xmeffdat * quotient(i))) print temp; i; esfchan(i) PUT #20, , chr(TEMP) curvol(i) = xmeffdat ELSEIF ctype(i) = 3 THEN effectdat(i) = &HC effectval(i) = xmeffdat PUT #20, , chr(&h2B) TEMP = INT(psgvol(xmeffdat * quotient(i))) PUT #20, , chr(TEMP) curvol(i) = xmeffdat ELSE 'ignore for pcm +noise effectdat(i) = 255 effectval(i) = 255 END IF END IF END IF NEXT i '''''''''''''''''''''''''''''''''''''''''''''''' Process current effects inbetween rows FOR pf = 1 TO TEMPo FOR i = 1 TO 11 SELECT CASE effectdat(i) CASE &h0 IF effectval(i) <> 0 THEN IF ctype(i) < 2 THEN SELECT CASE pf MOD 3 CASE 0 slidestep(i) = curnote(i) CASE 1 slidestep(i) = curnote(i) + arpnote1(i) CASE 2 slidestep(i) = curnote(i) + arpnote2(i) END SELECT WriteNote(slidestep(i)) END IF END IF CASE &hA 'Volume slide. one tick is (ticks per row - 1) from real volume ( 0 to 63) IF pf < effectval(i)+1 THEN IF ctype(i) <> 2 THEN IF volslidepos(i) < 65 AND volslidepos(i) > 0 THEN volslidepos(i) = volslidepos(i) + volslidespeed(i) IF volslidepos(i) < 0 THEN volslidepos(i) = 0 if ctype(i) = 1 then print volslidepos(i) curvol(i) = volslidepos(i) ELSE END IF IF volslidepos(i) < 65 AND volslidepos(i) > -1 THEN IF ctype(i) = 0 THEN PUT #20, , chr(esfchan(i) + &H20) PUT #20, , chr(fmvol(quotient(i) * volslidepos(i))) ELSE IF ctype(i) = 3 THEN PUT #20, , chr(&H2A) ELSE PUT #20, , chr(esfchan(i) + &H20) TEMP = INT(psgvol(quotient(i) * curvol( i))) PUT #20, , chr(TEMP) END IF END IF END IF END IF CASE 1 TO 3 if slidespeed(i) = -255 then print "SLIDESTEP: "; slidestep(i) slidestep(i) = slidestep(i) + slidespeed(i) / 16 IF slidespeed(i) < 0 AND slidetarget(i) > slidestep(i) THEN slidestep(i) = slidetarget(i) IF slidespeed(i) > 0 AND slidetarget(i) < slidestep(i) THEN slidestep(i) = slidetarget(i) WriteNote(slidestep(i)) CASE 4 vibstep(i) = vibstep(i) + vibspeed(i)*4 conversion = SIN(pi/180 * vibstep(i))*vibdepth(i)/5 + curnote(i) slidestep(i) = conversion WriteNote(slidestep(i)) END SELECT NEXT i PUT #20, , chr(&HFE) PUT #20, , chr(&H1) NEXT pf NEXT currow IF esfloop = 0 THEN PUT #20, , chr(&hFF) ELSEif restart > 0 then ' Restore instruments on looping FOR i = 1 TO 11 IF loopins(i) <> curins(i) AND i <> 10 THEN PUT #20, , chr(&H40 + esfchan(i)) PUT #20, , chr(INT(esfins(loopins(i)))) END IF NEXT i PUT #20, , chr(&hFC) ELSE PUT #20, , chr(&hFC) end if PRINT "Conversion done!" CLOSE END DATA 851, 803, 758, 715, 675, 637, 601, 568, 536, 506, 477, 450, 425, 401, 379, 357, 337, 318, 300 DATA 284,268,253,238,225,212,200,189,178,168,159,150,142,134,126,119,112,106,100 DATA 94, 89, 84, 79, 75, 71, 67, 63, 59, 56, 53, 50, 47, 44, 42, 39, 37, 35, 33 DATA 31, 29, 28, 26, 25, 23, 22, 21, 19, 18, 17, 16, 15, 14, 14