• Welcome to Final Fantasy Hacktics. Please login or sign up.
 
March 19, 2024, 07:04:47 am

News:

Please use .png instead of .bmp when uploading unfinished sprites to the forum!


Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Messages - lirmont

1
The Lounge / Re: Cake
April 13, 2015, 07:50:26 pm
Happy birthday! That slice of cake probably likes swords. That's probably why it's here.
2
If the amount of development per minute metric is your qualm with the first episode, I'd suggest that it evens out across the first season, and certainly across the whole show (up to the current ending). The first episode, as compared to a faster medium (like the plays we've talked about), contains a lot of setup events that prepare context and meaning for the development that does happen throughout the series. In season one, it's centered around Eddard Stark and his family as a counter-point to the other families in the show. He's not in season 2 because he's dead by episode 9. You've seen episode 1. How do you think he dies? There's an act that foreshadows it in one of the opening scenes.

As for clever lines, the series isn't clever in that regard; it's viral. Phrases are repeatable, like "My dragons!!!!!1111", "You know nothing, Jon Snow," and "Lannister's always pay their debts." Toss any of those into google. FFT's translation is similar in that respect, with unintentional gems like, "This is the way!" and "I got a good feeling!"
3
I think you missed a lot of the things you said don't exist in that first episode. As for music, it's the title theme that's important, rather than individual characters (though individual characters may temporarily grasp its attention); the show makes it a point to claim that people don't permanently matter, just places/concepts (like the Iron Throne). As for leitmotifs, they show up in the form of character foils (an example from the first episode are the animals that get found then raised by the Stark children; they continue to be used this way). Furthermore, the motivation for the whole show is the concept of "winter is coming". If you didn't pick up on that, it's the show's ragnarok/apocalypse/doomsday in the form of an invasion coming from the north to the south (i.e. where all civilization is). Also, I think it's difficult to sustain the description of "high-brow melodrama" after the first episode. It's downhill from the first episode. Would you call the content of some of Shakespeare's works (which include about as many murders) high-brow just because they're written in what sounds to us as archaic language? That seems like the comparison you're making.

And since you sound like you want to dismiss the show anyway, you might enjoy these:



4
The Rafa scene reminds me a little of the content in that show. If FFT were a show, it'd probably focus on how Ramza deals with being branded a heretic and how Delita tries to manipulate all the things. The show doesn't do much with religion (outside of a certain specific character), however there's lots of mysticism which you might equate to how the zodiac stones are handled in FFT. Additionally, most characters in the show aren't doing things on a misunderstanding (willful ignorance sometimes but not a misunderstanding), though mistakes being made out of grief is a recurring theme. FFT, on the other hand, has a lot of misguided characters. They're also usually well-meaning in FFT, but these characters go into brick wall mode once they decide to do something. The show's characters are mostly just out for themselves, though some stand-out characters are devoted to the general suffering of others. Maybe the most important difference is that FFT has a sense of joining up, whereas the show has a sense of painful isolation (most of the armies shown are short-lived).

One-for-one similarities:

  • Dragons

  • Dragon tamers

  • Collusion of power across governmental/social lines

  • Long-running kidnappings

  • Temporary imprisonment of important characters

  • Aggrandized nobles as knights

  • Traps (certain storylines only)

  • Undertones of poverty as a result of the elite class (l i t t l e m o n e y)

  • Demons

  • Undead

  • Contracted assassins

  • Boats

  • Regency/young royalty

  • Distant father figures

  • Sibling dynamics

  • Bastard sons

  • Pubs

  • Castle crashing

  • Sidekicks

  • Travel theme

  • Robbery

  • Factions/orders/groups outside of government

  • Super-powered/super-rare swords

  • Unsolved/unclaimed murder by poison

  • Churches

  • Political marriages



Things FFT has:

  • Guns

  • Robots

  • A vampire

  • Japanese cultural occupations

  • A volcano?

  • Multiple dimensions?

  • Religion as an overtone

  • All manner of magic

  • Handbags?

  • Banned books?



Things GoT has:

  • Slavery

  • Brothels

  • A banking institution

  • Cruel and unusual punishment

  • Overly attached mothers

  • Mythologies for their royalty

  • Disfigurement theme

  • Debt/credit

  • Spying

  • Religion as an undertone

5
Spam / Re: WHY?!
December 09, 2014, 04:14:56 pm
Here's a hypothetical situation. Imagine that the original game is represented in a ball form. Now, the ball can bounce around, roll, be still, entertain, etc, but, no matter what you do, the ball stays together because the ball is cohesive. Now, as time goes on, the ball may be seen to be less fun to play with because it lacks things other newer forms of entertainment possess. Reasonably speaking, releasing the next version of this ball should probably just bring the ball up to date so that it can compete for attention well against other entertainment products: new packaging, refurbishing old parts so that they thrive in modern environments, and re-advertising the product (harkening back to what made it great at what it did previously).

Enter War of the Lions. Instead of (just) bringing the old game up to date, they made something akin to a lava lamp, tossing an old game in to drift aimlessly around for the rest of forever amidst the newer, brightly-colored lava lamp goop and to bang into the smaller representations of other games also dumped into said goop. Can lava lamps be entertaining? Sure, but are they a cohesive mixture anymore? No, and so my personal dislike comes from the fact that I don't see FFT:WotL as a cohesive game. I see it as "game-ish"; there's a cohesive game somewhere in there (sometimes it even rises to the forefront) but it's lost amongst other things.

If you were to order a smoothie and that "smoothie" was just unblended fruit in an attractive cup, would you like the product as a smoothie?
6
The Lounge / Re: FF7 - PS4 Port
December 07, 2014, 08:12:29 pm
Rejected titles:

  • "FF7 - Coming to an Emulator Near You",

  • "FF7 - The Promo Video Was a Significant Portion of the Budget",

  • "FF7 - The Promo Video is More Computationally Intensive Than the Game",

  • "FF7 - This is What You Wanted, Right? #tooSoon", and

  • "FF7 - #sorryNotSorry".
7
Help! / Re: Battle Sound Mod
November 21, 2014, 03:09:37 pm
FFT uses MIDI-quality music, which basically means you need to know what the notes in the song are and for how long they play. You cannot currently put modern audio files in (like MP3s).

The easiest place to start is here: MIDI to SMD v0.5: FFT Music Converter.

You may also need to consult:

8
Final Fantasy Tactics / Re: Final Fantasy Fractics
October 30, 2014, 12:37:15 am
Besides The Neverending Story, there's the Myst series, where book writing and book travel are entrenched mechanics. They also have copious amounts of odd-sounding names (like Atrus).
9
Alright, here it is (same link): download.

It's not 100%, but I believe it will suit your purposes: (1) combo box drop downs use available space (sometimes less options are shown on purpose, though), (2) no controls overlap, and (3) the "Patch ISO" screens are sizable now. Things I know are still wrong: (1) doesn't handle big fonts, (2) controls near edges of parents sometimes get cut off (change to smaller font), and (3) animation tab takes a long time to load (but it looks nice).

Here is a screenshot:


10
The setting for how many drop down items to show can be overridden easily enough in the code. I'll start working on the rest of the layouts now.
11
Spam / Re: Purses as weapons
July 17, 2014, 01:07:59 am
Little Ol' Lady, Lv. 99
Master Bag Lady (Lv. 8)

Actions

  • Accumulate Sweets

  • Squint

  • Pinch

  • Head Shake

  • LOUD NOISES


Reaction/Support/Movement

  • Ignore Speed Limit

  • Equip EZ-Reacher

  • Cooking +3

  • Kitsch +5

  • Thrift

12
Okay, then please check the "Items" tab for me of this version: download. It takes a lot of work to reorganize the layout into this format, but, if that tab is laid out how you expect (undo any changes you've done to the XP theme), I don't mind doing it for the rest of them. This version also benefits from the whole form's size, meaning you can see more options at any given time. Again, the "Items" tab is the only one I've done it for, and that took over an hour.

This is what it looks like:


13
The goal of the version I reconfigured wasn't to let you use the font you had (i.e. the problem font). The goal was to let you set Tahoma (i.e. the font it was designed for) in the theme so that it will look like it was designed to look. There are two problems: (1) the font and (2) the button size XP's button skins add to the really small, nearly absolutely positioned numeric up/down controls. The first issue causes overlaps like the "Effect:" over the combo box; this is the font's fault (i.e. temporarily switch to Tahoma in the theme). The second issue causes overlaps like when the numeric up/down controls would overlap each other (i.e. you could turn the theme to classic in XP which doesn't have those huge button skins, but the version I reconfigured turns that off just for the application).
14
This Version


Here's a version of that program that doesn't turn visual styles on: download. There were also a couple of other things that weren't configured to have the font changed (the Patch ISO windows, for instance; also, the item heights of the ENTD unit list). This addresses those. As per the previous post, it looks for the font you set in the theme under "Message Box" (whereas the previous version didn't). The visual styles are turned off to prevent the blue buttons (which are large) from winding up on the numeric up/down controls.
15



  • Open FFTPatcher to the window you're having trouble with.

  • Right-click somewhere empty on the desktop.

  • Select "Properties" from the context menu.

  • Select the "Appearance" tab.

  • Click the "Advanced" button.

  • Choose a different font and size until the program looks like you want it to (hit "OK" then "Apply"; NOTE: the program probably expects Tahoma 8pt).

  • Optional: Change the font back afterwards.



Windows Forms applications provide programmers with the ability to auto-size their components. In other words, were all the components a size that fit your personal choice of desktop font? Probably. Ideally, these auto-size components (like the numeric up and down controls) could increase in size and decrease in size without having to worry about their actual placement on a form; Windows Forms is designed to do that. However, those components have to actually be inside of a container that lays them out properly (based on new heights and widths). Instead, if the component is just anchored to the form, you'll see components start to overlap (like in the screenshots you posted). That's a problem with the application, but, rather than re-do the layout, you can just change the font to fall back to what the application expected your font to look like.
16
The font is wide (i.e. change it in the theme to one that's less wide with less vertical spacing).
17
PSX FFT Hacking / Re: Waveform/Instrument Injection
July 05, 2014, 09:53:03 pm
Something else maybe worth looking at is that PSound finds 2 really short audio files in BATTLE.BIN. I found them at 0x2d4e0-0x2d760 (185568-186208) and 0x2eaa7-0x2eca6 (191143-191654). Might be an easy target for a quick customization. I think the first one might be the gil award plink (it's 0.05s). I don't know what the second one is, but it's 0.04s.
18
PSX FFT Hacking / Waveform/Instrument Injection
July 04, 2014, 02:35:12 am
New instruments in FFT!



--

Have not decoded the actual definitions for instruments yet. Have managed to replace the wave data (WAVESET.WD) that they operate on.

Involved files:

  • WAVESET.WD (wave data)

  • The ISO it's on.



Process:

  • Drag WAVESET.WD into the PSound program.

  • PSound will show 85 waves (0..84).

  • Pick the sound you want to replace.

  • Export the sound (after configuring PSound to not add extra lead out).

  • Document how long the sound is for reference in picking a replacement .WAV file (NOTE: .WAV file should be 22050Hz, 16-bit PCM).

  • Open WAVESET.WD in a hex editor.

  • The first waveform in that file is at 0x0b40; you can identify waves after this point in the file by a sequence of 16 or more consecutive empty bytes; the data streams start as soon as the first non-zero 2-byte set is encountered (like 0x00 0x02 or 0x05 0x02).

  • Jump to the waveform you want to replace.

  • Determine the length to the next set of 16 empty bytes from the start of the data set. This number is the length in bytes of the data streams in the waveform.

  • Use the following program I wrote to encode your wave file like: python wave-to-playstation-encoding.py WaveFileName.wav LengthInBytes

  • There is now a file containing the data: WaveFileName.wav.bytes

  • In a hex editor that supports paste overwrite (re: the HxD program), paste over the existing data streams back in the WAVESET.WD file.

  • Clear PSound's playlist, and reload the file by dragging it into the playlist area.

  • If you copied the data over correctly, you'll hear the new wave. If not, you'll hear a stock, choppy wave that PSound plays when it can't decode the data (you can just think of it as an error beep).

  • When you're happy with it, you'll need to replace the WAVESET.WD file in the ISO.

  • To do this part manually, open your ISO in a hex editor, and search for the text string: dwdsP (or the hex string 64776473502016CE). This is the start of the WAVESET.WD file in the ISO.

  • Locate the wave you want to replace after that point.

  • Waveforms contain an unbroken line of 2-byte commands that you can see clearly in a standard 16-byte view (re: look for the column of 0x02, 0x06, or 0x03 bytes). Highlight the data stream until you encounter non-file data (i.e. where there would be a two byte command like 0x00 0x02 there is instead a FE FF). Record this value as the initial write for the file.

  • Now, continue highlighting all the way down to just before the next set of consecutive 16 empty bytes (0x03 in the second command byte signals the last stream of the waveform). Copy this data into an ANSI text file (like 0010.txt), removing the spaces between bytes with a replace all tool.

  • Now, re-encode the replacement WAV file against the ISO's data, like: python wave-to-playstation-encoding.py WaveFileName.wav LengthInBytes TextFileWithBytesFromISO.txt InitialWriteAsNumberOrHexadcimal

  • The content of the resulting .bytes file can be copied over the data stream in the ISO in the same way as the file (paste write).

  • Your ISO now contains a different sound than FFT shipped with.



Usage (for the test in the video on a Japanese ISO of FFT).
Code (Command Line) Select
python wave-to-playstation-encoding.py C1.wav 6816 C1.txt 0x360
python wave-to-playstation-encoding.py C2.wav 3808 C2.txt 0xb0
python wave-to-playstation-encoding.py C3.wav 3936 C3.txt 0x1c0
python wave-to-playstation-encoding.py C4.wav 1472 C4.txt 0x250
python wave-to-playstation-encoding.py C5.wav 3104 C5.txt 0x480


wave-to-playstation-encoding.py
NOTE: Requires installing Python and several dependencies: numpy and scipy.

Code (Python) Select

import numpy as np
from itertools import product
from scipy.io.wavfile import read

# Pass through values that line up with offsets: 0x0 to 0xf.
acceptedValues = [0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, -1.0, -0.875, -0.75, -0.625, -0.5, -0.375, -0.25, -0.125]
acceptedValuesMaxArray = np.array([0.875, -1, ])
allValueRange = np.array(acceptedValues)
# SYNONYMS: 0x06 and 0x03. 0x06 may be some kind of off switch to something 0x02 can do in effects. 0x03 signals the last block follows. They don't do anything special to the data, though.
amplitudeCommands = [0x02, ]
# Cutoff seemed like < 0x5d. Also, cannot use anything evenly divisible by any in range: (0xd, 0xe, 0xf). However, everything above the first 16 (with the exception of the 0x5x block, which is a pass through exactly? the same as 00) are effects, and can safely be ignored for the purposes of writing pre-amplified data into the waveform.
exponents = [i for i in range(0, 0x10) if (i == 0) or ((i % 0xd) > 0) and ((i % 0xe) > 0) and ((i% 0xf) > 0)]
negativePowersOfTwo = list(product(amplitudeCommands, exponents))

# Yield successive n-sized chunks from l. Used to slice bytes of an incoming wave into 28-sample sets (encodes to 14 bytes).
def chunks(l, n):
for i in xrange(0, len(l), n):
yield l[i:i+n]

# Convert sample value (expects 16-bit signed integer) into a value from -1 to 1.
def getSampleValue(n):
thisSampleValue = np.nan_to_num(n) / 32767.0
return thisSampleValue

# Rounds actual data to data represented in the encoding scheme.
def roundToNearestAcceptedValue(sampleValue, valueRange = None):
valueRange = valueRange if valueRange is not None else allValueRange
delta = None
actualNumber = None
for possibility in valueRange:
thisDelta = abs(sampleValue - possibility)
#
if (delta is None) or (thisDelta < delta):
delta = thisDelta
actualNumber = possibility
return actualNumber

# For values of 0x0 to 0xc in command 0x02, yield: 2**(-n). Values in 0x1x range are a concave falloff. Values in 0x2x range are a convex falloff. Values in 0x3x range are a whole sine wave. Values in 0x4x range are the first 4/5th's of a sine wave.
def getModifier(value):
return 1 / float(2 ** value)

# Get the closest amplitude modifier in the encoding scheme. Intended for use with maximum values.
def getClosestModifier(value, valueRange = acceptedValuesMaxArray, negativePowersOfTwo = negativePowersOfTwo):
# If the value is not zero, go looking for it as a max/min value in the sliding table of values.
if value != 0:
delta = None
actualNumber = None
actualModifier = None
for idx, (command, power) in enumerate(negativePowersOfTwo):
try:
# Typically, get the value of: 1 / 2**power.
modifier = getModifier(power)
# See if any of the maximum values are now equivalent to the supplied value.
for possibility in (valueRange * modifier):
thisDelta = abs(value - possibility)
# If this value is closer than previous values, store it as new solution to best-fit question.
if (delta is None) or (thisDelta < delta):
# Try to escape early. The delta is an exact match.
if thisDelta == 0:
return actualModifier
# Otherwise, store best and continue.
else:
delta = thisDelta
actualNumber = possibility
actualModifier = idx
except:
pass
return actualModifier
# If the value is zero, it can be represented in the pass through, which will be data set (2, 0) at index 0 of negativePowersOfTwo.
else:
return 0

# Translate the 28-sample set into a 16-byte data stream of form: AACC 00112233445566778899AABBCCDD
def getBytesForStream(dataStream):
samples = np.array([getSampleValue(rawValue) for rawValue in dataStream])
maximumValue = samples[abs(samples).argmax()] #max([abs(sample) for sample in samples])
# Store bytes for wave amplitude modifier and stream.
modifierBytes = [0x0, 0x2]
bytes = []
# If the maximum value is not in the default max values list, look it up. Majority case.
modifierIndex = getClosestModifier(maximumValue)
command, power = negativePowersOfTwo[modifierIndex]
thisModifier = getModifier(power)
modifierBytes = [power, command]
scaledDefaultValues = allValueRange * thisModifier
roundedValues = [roundToNearestAcceptedValue(sampleValue, valueRange = scaledDefaultValues) for sampleValue in samples]
# Find indices of values in list.
scaledDefaultValues = list(scaledDefaultValues)
indices = [scaledDefaultValues.index(roundedValue) for roundedValue in roundedValues]
# Get (1, 2), (3, 4), ... (n, n + 1).
groupedIndices = [(indices[i], indices[i+1]) for i in range(0, len(indices), 2)]
# Write the bytes out.
bytes = [] + modifierBytes
for start, finish in groupedIndices:
# Calculate the 2-dimensional array offset in hex of the sliding table values.
x = start * (16 ** 0) + finish * (16 ** 1)
bytes.append(x)
#
return bytes

# Process all the data of the incoming wave.
def processData(data, samplesPerByte = 2, waveFormBytesPerStream = 14, limit = None):
# Typically: 2 compression modulation bytes followed by compressing 28 bytes into 14 bytes such that 1 byte equals 2 samples. Total: 16 bytes per stream.
fourteenByteDataStreams = chunks(data, waveFormBytesPerStream * samplesPerByte)
# Store return data in string (intended for pasting in a hex editor).
result = ""
totalBytes = 0
# For each stream, bet the bytes.
for dataStream in fourteenByteDataStreams:
theseBytes = getBytesForStream(dataStream)
count = len(theseBytes)
# If this is the last stream to be written, signal with 0x03 instead of 0x02 (or 0x06). Then quit.
if (limit is not None) and (totalBytes + count) >= limit:
theseBytes = theseBytes[0:limit - totalBytes]
theseBytes[1] = 0x03
result += "".join(["%02X" % byte for byte in theseBytes])
totalBytes += len(theseBytes)
break
# Otherwise, add in form of AACC00112233445566778899AABBCCDD.
else:
result += "".join(["%02X" % byte for byte in theseBytes])
totalBytes += len(theseBytes)
return result

# For arguments, accept: 37 (or) 0x25, 0x800 (or) 2048, etc.
def hexOrInteger(inputString):
try:
return int(inputString)
except ValueError:
return int(inputString, 16)
return 0

# Usage: python wave-to-playstation-encoding.py WaveFile.wav
# Crossed Streams Usage (short): python wave-to-playstation-encoding.py WaveFile.wav OtherStream.txt InitialWriteFor
# Crossed Streams Usage: python wave-to-playstation-encoding.py WaveFile.wav OtherStream.txt InitialWriteFor OtherStreamWriteFor ThisStreamWriteFor
if __name__ == "__main__":
import sys
# Arguments: No input file.
if len(sys.argv) == 1:
print "No input file. Usage: python %s WaveFile.wav\nCross Stream Usage: python %s WaveFile.wav OtherStream.txt InitialWriteFor OtherStreamWriteFor ThisStreamWriteFor\nNOTE: ANSI files only." % (sys.argv[0], sys.argv[0])
sys.exit()
# Arguments: No length.
if len(sys.argv) == 2:
sys.argv.append(None)
# Turn length into an integer.
else:
sys.argv[2] = hexOrInteger(sys.argv[2])
# Arguments: Cross stream file.
if len(sys.argv) == 3:
sys.argv.append(None)
# Arguments: Cross stream initial write for.
if len(sys.argv) == 4:
sys.argv.append(0)
# Turn initial write for into integer.
else:
sys.argv[4] = hexOrInteger(sys.argv[4])
# Arguments: Cross into other stream for.
if len(sys.argv) == 5:
sys.argv.append(0x130)
# Turn cross into other stream for into integer.
else:
sys.argv[5] = hexOrInteger(sys.argv[5])
# Arguments: Cross back into this stream for.
if len(sys.argv) == 6:
sys.argv.append(0x800)
# Turn cross back into this stream for into integer.
else:
sys.argv[6] = hexOrInteger(sys.argv[6])
# Arguments.
thisFilename, waveFilename, length, fileWithStreamFromISO, initialWriteFor, otherStreamWriteFor, thisStreamWriteFor = sys.argv
# Print back the filename for reference.
print waveFilename
# Read data.
rate, data = read(waveFilename)
# Get the bytes of the file body.
result = processData(data, limit = length)
if fileWithStreamFromISO is not None:
crossedStream = ""
parts = []
currentFileCaret = 0
currentResultCaret = 0
resultLength = len(result)
# Read the other stream.
with open(fileWithStreamFromISO, "r") as f:
stream = f.read()
# Initial write (write X bytes of the result).
count = initialWriteFor * 2
currentFileCaret += count
currentResultCaret += count
parts.append(result[0:currentFileCaret])
# Enter into a loop of crossing back and forth between the other stream and the result stream.
while currentResultCaret < resultLength:
# Write from other stream.
count = otherStreamWriteFor * 2
parts.append(stream[currentFileCaret:currentFileCaret+count])
currentFileCaret += count
# Write from this stream.
if currentResultCaret < resultLength:
count = thisStreamWriteFor * 2
actualEnd = min(resultLength, currentResultCaret + count)
count = (actualEnd - currentResultCaret)
parts.append(result[currentResultCaret:actualEnd])
currentFileCaret += count
currentResultCaret += count
crossedStream = "".join(parts)
# Print the byte count of the combined streams.
print "Bytes:", (len(crossedStream) / 2)
# Write the bytes out to a text file (for copying into a hex editor).
with open("%s.bytes" % waveFilename, "w+") as f:
f.write(crossedStream)
else:
# Print the byte count of the result.
print "Bytes:", (len(result) / 2)
# Write the bytes out to a text file (for copying into a hex editor).
with open("%s.bytes" % waveFilename, "w+") as f:
f.write(result)
19
PSX FFT Hacking / Re: SMD Parser (WIP)
June 27, 2014, 06:00:02 am
Let the most bizarre game of "Name That Instrument" begin: Instruments.

--

Disgaea's "Red Moon" (as found on VGMusic)



Instruments 41 and 42 (main, accompaniment).

--

I have discovered what offset 0x1A-0x1B (bytes 26 and 27) is (part of the 3rd unknown block on this page: Music/SMD). This sound file demonstrates a kind of reverb for values of 0 (0x0 0x0), 1084 (0x02 0x1e), and 15364 (0x04 0x3c; what FFT SMDs have): listen.

--

I'm sure it's been explained elsewhere about the SMD format, but most of the stuff is not complicated (considering they're mostly just MIDI files, which is a mature specification even back in 1997).

To help visualize the songs, I've added the feature to plot the notes and instruments out (because I'm having trouble finding suitable alternatives for the samples FFT used). If you can understand something like the graphs, I can probably set it up to interactively change the note (because the graphing application already supports interactivity). However, that won't cover any of the effects (and MIDI files depend on them to make engaging music).

The following are note graphs for two songs (songs provided).

LvUp L (i.e. "MUSIC_24.SMD") (listen)




KUMA BALL (i.e. "MUSIC_25.SMD", Mr. Bear Goes to the Ball) (listen)
Bass line only.



View: larger.
20
PSX FFT Hacking / SMD Parser (WIP)
June 25, 2014, 02:41:21 pm
I know there's already something that will get a MIDI into SMD format. I was curious to get the notes out of an SMD, though. This is the file "MUSIC_24.SMD" (LvUp L) with varying MIDI instruments: MUSIC_24.mp3.

As soon as I finish cleaning up the code, I'll post a link here. I believe some of the unknowns point to the information the BGM test shows (an actual title, author, and help text), but I wasn't that curious.

Name: music_24
Tracks: 10
Path: MUSIC_24.SMD
Start Track #1
    Set tempo to 128 (128/102 * 120bpm).
    Set time signature to 4/4.
    BEGIN LOOP, Loop x3
        Rest for 192/192 of a whole note.
    END LOOP
End Track.
Start Track #2
    Set volume to 30/127.
    Set balance to 64/127 towards right speaker.
    Set instrument to 79.
    Set octave to 5.
    C5 (74%) for 6% of a whole note, NOTE ON
    Rest for 60/192 of a whole note.
    F5 (74%) for 6% of a whole note, NOTE ON
    Rest for 84/192 of a whole note.
    C5 (74%) for 6% of a whole note, NOTE ON
    Rest for 12/192 of a whole note.
    Rest for 48/192 of a whole note.
    F5 (74%) for 6% of a whole note, NOTE ON
    Rest for 36/192 of a whole note.
    Set instrument to 80.
    C#5 (74%) for 12% of a whole note, NOTE ON
    Rest for 24/192 of a whole note.
    Set instrument to 79.
    C#5 (74%) for 6% of a whole note, NOTE ON
    Rest for 36/192 of a whole note.
    C5 (74%) for 6% of a whole note, NOTE ON
    Rest for 144/192 of a whole note.
    Rest for 36/192 of a whole note.
End Track.
Start Track #3
    Set volume to 30/127.
    Set balance to 64/127 towards right speaker.
    Rest for 48/192 of a whole note.
    Set instrument to 80.
    Set octave to 4.
    G4 (74%) for 6% of a whole note, NOTE ON
    Rest for 60/192 of a whole note.
    A#4 (74%) for 6% of a whole note, NOTE ON
    Rest for 48/192 of a whole note.
    Rest for 12/192 of a whole note.
    Rest for 24/192 of a whole note.
    G4 (74%) for 12% of a whole note, NOTE ON
    Rest for 24/192 of a whole note.
    Increment octave from 4 to 5.
    C5 (74%) for 6% of a whole note, NOTE ON
    Rest for 36/192 of a whole note.
    Decrement octave from 5 to 4.
    A#4 (74%) for 6% of a whole note, NOTE ON
    Rest for 36/192 of a whole note.
    Set instrument to 79.
    A#4 (74%) for 6% of a whole note, NOTE ON
    Rest for 12/192 of a whole note.
    Rest for 192/192 of a whole note.
End Track.
Start Track #4
    Set volume to 36/127.
    Set balance to 64/127 towards right speaker.
    Set instrument to 70.
    Set octave to 6.
    C6 (78%) for 4% of a whole note, NOTE ON
    Rest for 64/192 of a whole note.
    Decrement octave from 6 to 5.
    G#5 (78%) for 3% of a whole note, NOTE ON
    Rest for 90/192 of a whole note.
    Increment octave from 5 to 6.
    C6 (78%) for 4% of a whole note, NOTE ON
    Rest for 16/192 of a whole note.
    Rest for 48/192 of a whole note.
    Decrement octave from 6 to 5.
    G#5 (78%) for 3% of a whole note, NOTE ON
    Rest for 42/192 of a whole note.
    C#5 (78%) for 12% of a whole note, NOTE ON
    Rest for 24/192 of a whole note.
    A#5 (78%) for 3% of a whole note, NOTE ON
    Rest for 36/192 of a whole note.
    Rest for 6/192 of a whole note.
    Increment octave from 5 to 6.
    C6 (78%) for 4% of a whole note, NOTE ON
    Rest for 144/192 of a whole note.
    Rest for 36/192 of a whole note.
    Rest for 4/192 of a whole note.
End Track.
Start Track #5
    Set volume to 36/127.
    Set balance to 64/127 towards right speaker.
    Set instrument to 70.
    Set octave to 5.
    G5 (78%) for 4% of a whole note, NOTE ON
    Rest for 64/192 of a whole note.
    D#5 (78%) for 3% of a whole note, NOTE ON
    Rest for 90/192 of a whole note.
    G5 (78%) for 4% of a whole note, NOTE ON
    Rest for 16/192 of a whole note.
    Rest for 48/192 of a whole note.
    D#5 (78%) for 3% of a whole note, NOTE ON
    Rest for 42/192 of a whole note.
    Decrement octave from 5 to 4.
    A#4 (78%) for 12% of a whole note, NOTE ON
    Rest for 24/192 of a whole note.
    Increment octave from 4 to 5.
    F#5 (78%) for 3% of a whole note, NOTE ON
    Rest for 36/192 of a whole note.
    Rest for 6/192 of a whole note.
    G5 (78%) for 4% of a whole note, NOTE ON
    Rest for 144/192 of a whole note.
    Rest for 36/192 of a whole note.
    Rest for 4/192 of a whole note.
End Track.
Start Track #6
    Set volume to 36/127.
    Set balance to 64/127 towards right speaker.
    Set instrument to 70.
    Set octave to 5.
    E5 (78%) for 4% of a whole note, NOTE ON
    Rest for 64/192 of a whole note.
    C5 (78%) for 3% of a whole note, NOTE ON
    Rest for 90/192 of a whole note.
    E5 (78%) for 4% of a whole note, NOTE ON
    Rest for 16/192 of a whole note.
    Rest for 48/192 of a whole note.
    C5 (78%) for 3% of a whole note, NOTE ON
    Rest for 42/192 of a whole note.
    Set instrument to 68.
    F#5 (78%) for 12% of a whole note, NOTE ON
    Rest for 24/192 of a whole note.
    Set instrument to 70.
    C#5 (78%) for 3% of a whole note, NOTE ON
    Rest for 36/192 of a whole note.
    Rest for 6/192 of a whole note.
    E5 (78%) for 4% of a whole note, NOTE ON
    Rest for 144/192 of a whole note.
    Rest for 36/192 of a whole note.
    Rest for 4/192 of a whole note.
End Track.
Start Track #7
    Set volume to 36/127.
    Set balance to 64/127 towards right speaker.
    Rest for 48/192 of a whole note.
    Set instrument to 70.
    Set octave to 5.
    G5 (78%) for 3% of a whole note, NOTE ON
    Rest for 66/192 of a whole note.
    F5 (78%) for 4% of a whole note, NOTE ON
    Rest for 64/192 of a whole note.
    Rest for 24/192 of a whole note.
    G5 (78%) for 12% of a whole note, NOTE ON
    Rest for 24/192 of a whole note.
    F5 (78%) for 3% of a whole note, NOTE ON
    Rest for 42/192 of a whole note.
    F#5 (78%) for 3% of a whole note, NOTE ON
    Rest for 42/192 of a whole note.
    Set instrument to 71.
    Increment octave from 5 to 6.
    C#6 (78%) for 3% of a whole note, NOTE ON
    Rest for 18/192 of a whole note.
    Rest for 192/192 of a whole note.
End Track.
Start Track #8
    Set volume to 36/127.
    Set balance to 64/127 towards right speaker.
    Rest for 48/192 of a whole note.
    Set instrument to 70.
    Set octave to 5.
    E5 (78%) for 3% of a whole note, NOTE ON
    Rest for 66/192 of a whole note.
    D5 (78%) for 4% of a whole note, NOTE ON
    Rest for 64/192 of a whole note.
    Rest for 24/192 of a whole note.
    E5 (78%) for 12% of a whole note, NOTE ON
    Rest for 24/192 of a whole note.
    D5 (78%) for 3% of a whole note, NOTE ON
    Rest for 42/192 of a whole note.
    C#5 (78%) for 3% of a whole note, NOTE ON
    Rest for 42/192 of a whole note.
    A#5 (78%) for 3% of a whole note, NOTE ON
    Rest for 18/192 of a whole note.
    Rest for 192/192 of a whole note.
End Track.
Start Track #9
    Set volume to 36/127.
    Set balance to 64/127 towards right speaker.
    Rest for 48/192 of a whole note.
    Set instrument to 70.
    Set octave to 5.
    C5 (78%) for 3% of a whole note, NOTE ON
    Rest for 66/192 of a whole note.
    Decrement octave from 5 to 4.
    A#4 (78%) for 4% of a whole note, NOTE ON
    Rest for 64/192 of a whole note.
    Rest for 24/192 of a whole note.
    Increment octave from 4 to 5.
    C5 (78%) for 12% of a whole note, NOTE ON
    Rest for 24/192 of a whole note.
    BEGIN LOOP, Loop x2
        Decrement octave from 5 to 4.
        A#4 (78%) for 3% of a whole note, NOTE ON
        Rest for 42/192 of a whole note.
    END LOOP
    Increment octave from 4 to 5.
    F#5 (78%) for 3% of a whole note, NOTE ON
    Rest for 18/192 of a whole note.
    Rest for 192/192 of a whole note.
End Track.
Start Track #10
    BEGIN LOOP, Loop x3
        Rest for 192/192 of a whole note.
    END LOOP
End Track.