Files
PokemonGameEditor/GBAPokemonGameEditor/CryFunctions.vb
Dreuu 93988a1330 Cry Compression Fix and other fixes/QOL improvements and refactoring
Cries:
-Importing a cry and compressing it now creates a more accurate, and less crackly cry in game.
-The cry repointer now works and correctly determines whether the cry was compressed or not.
-The cry screen now forces all pointers/info to update before switching to the next pokemon instead of only updating after you stop switching pokemon.(If you scroll fast, you will still see all information.)

Pokemon Editor:
-Fied a bug where some base stats weren't read correctly, Base Happiness, Gender Ratio...
-Refactored Base State reading so there is only one big read instead of dozens of small reads.
-Fixed a bug where the "Facing Left/Right in status screen" radio buttons didn't populate.

Item Editor:
-Refactored the read/write code to minimize the number of reads and writes. Shouldn't affect much. Maybe slightly faster import/export.
2019-01-13 21:32:17 -05:00

735 lines
28 KiB
VB.net

Imports System
Imports System.IO
Imports System.Text
Imports System.Media
Imports VB = Microsoft.VisualBasic
'These functions are based off the ones found in this project: https://github.com/doom-desire/Cry-Editor
'Credit goes to doom-desire for these functions.
Module CryFunctions
Structure Cry
Public Index As Integer
Public Offset As Integer
Public Compressed As Boolean
Public Looped As Boolean
Public SampleRate As Integer
Public LoopStart As Integer
Public Size As Integer
Public Data As SByte()
End Structure
Public Function LoadCry(index As Integer, cryTable As Integer) As Cry
'If ledrom Is Nothing Then
' Return False
'End If
' load cry table entry
'ledrom.Seek(cryTable + index * 12)
'Dim someValue = ledrom.ReadInt32()
'Dim cryOffset = ledrom.ReadPointer()
'Dim cryShape = ledrom.ReadInt32()
Dim CryToLoad As New Cry With {
.Index = index
}
Dim convIndex As Integer = -1
If index > 276 Then
Dim offset As Integer = Int32.Parse((GetString(GetINIFileLocation(), header, "CryConversionTable", "")), System.Globalization.NumberStyles.HexNumber)
convIndex = Int32.Parse((ReverseHEX(ReadHEX(LoadedROM, ((offset)) + ((index - 276) * 2), 2))), System.Globalization.NumberStyles.HexNumber)
End If
Dim someValue = Int32.Parse(ReverseHEX((ReadHEX(LoadedROM, (cryTable) + (index * 12), 4))), System.Globalization.NumberStyles.HexNumber)
Dim cryOffset = (Int32.Parse(ReverseHEX((ReadHEX(LoadedROM, (cryTable) + (index * 12) + 4, 4))), System.Globalization.NumberStyles.HexNumber) - &H8000000)
Dim cryShape = Int32.Parse(ReverseHEX((ReadHEX(LoadedROM, (cryTable) + (index * 12) + 8, 4))), System.Globalization.NumberStyles.HexNumber)
'If cryOffset = 0 Then
' Return False
'End If
' load cry data
'ledrom.Seek(cryOffset)
CryToLoad.Offset = cryOffset
If convIndex <> -1 Then
someValue = Int32.Parse(ReverseHEX((ReadHEX(LoadedROM, (cryTable) + (convIndex * 12), 4))), System.Globalization.NumberStyles.HexNumber)
cryOffset = (Int32.Parse(ReverseHEX((ReadHEX(LoadedROM, (cryTable) + (convIndex * 12) + 4, 4))), System.Globalization.NumberStyles.HexNumber) - &H8000000)
cryShape = Int32.Parse(ReverseHEX((ReadHEX(LoadedROM, (cryTable) + (convIndex * 12) + 8, 4))), System.Globalization.NumberStyles.HexNumber)
CryToLoad.Offset = cryOffset
End If
'CryToLoad.Compressed = ledrom.ReadUInt16() = &H1
'CryToLoad.Looped = ledrom.ReadUInt16() = &H4000
'CryToLoad.SampleRate = ledrom.ReadInt32() >> 10
'CryToLoad.LoopStart = ledrom.ReadInt32()
'CryToLoad.Size = ledrom.ReadInt32() + 1
CryToLoad.Compressed = Int16.Parse(ReverseHEX((ReadHEX(LoadedROM, (cryOffset) + 0, 2))), System.Globalization.NumberStyles.HexNumber) = &H1
CryToLoad.Looped = Int16.Parse(ReverseHEX((ReadHEX(LoadedROM, (cryOffset) + 2, 2))), System.Globalization.NumberStyles.HexNumber) = &H4000
CryToLoad.SampleRate = Int32.Parse(ReverseHEX((ReadHEX(LoadedROM, (cryOffset) + 4, 4))), System.Globalization.NumberStyles.HexNumber) >> 10
CryToLoad.LoopStart = Int32.Parse(ReverseHEX((ReadHEX(LoadedROM, (cryOffset) + 8, 4))), System.Globalization.NumberStyles.HexNumber)
CryToLoad.Size = Int32.Parse(ReverseHEX((ReadHEX(LoadedROM, (cryOffset) + 12, 4))), System.Globalization.NumberStyles.HexNumber) + 1
If Not CryToLoad.Compressed Then
' uncompressed, 1 sample per 1 byte of size
CryToLoad.Data = New SByte(CryToLoad.Size - 1) {}
Dim cryToLoadTemp As String = ReadHEX(LoadedROM, (cryOffset) + 16, CryToLoad.Size - 1)
For g As Integer = 0 To CryToLoad.Size - 2
CryToLoad.Data(g) = ByteToSignedInt("&H" & cryToLoadTemp.Substring(g * 2, 2))
Next
'For g As Integer = 0 To CryToLoad.Size - 1
' CryToLoad.Data(g) = ByteToSignedInt("&H" & (ReadHEX(LoadedROM, (cryOffset) + 16 + g, 1)))
'Next
Else
' compressed, a bit of a hassle
Dim lookup = New SByte() {0, 1, 4, 9, 16, 25,
36, 49, -64, -49, -36, -25,
-16, -9, -4, -1}
Dim start = (cryOffset) + 16
Dim offtrack = (cryOffset) + 16
Dim alignment As Integer = 0, size As Integer = 0
Dim pcmLevel As SByte = 0
Dim pcmTemp As Int16 = 0
Dim data = New List(Of SByte)()
Dim cryData As String = (ReadHEX(LoadedROM, offtrack, CryToLoad.Size))
offtrack = 0
While True
If alignment = 0 Then
pcmLevel = ByteToSignedInt("&H" & cryData.Substring(offtrack, 2)) '(ReadHEX(LoadedROM, offtrack, 1)))
pcmTemp = pcmLevel
offtrack = offtrack + 2 '1
data.Add(pcmLevel)
alignment = &H20
End If
Dim input As Byte = ("&H" & cryData.Substring(offtrack, 2)) '(ReadHEX(LoadedROM, offtrack, 1)))
offtrack = offtrack + 2 '1
If alignment < &H20 Then
If Int16.Parse(pcmLevel) + lookup(input >> 4) < -128 Then
pcmLevel = 128 + lookup(input >> 4)
ElseIf Int16.Parse(pcmLevel) + lookup(input >> 4) > 127 Then
pcmLevel = -129 + lookup(input >> 4)
Else
pcmLevel += lookup(input >> 4)
End If
data.Add(pcmLevel)
End If
' second nybble
If Int16.Parse(pcmLevel) + lookup(input And &HF) < -128 Then
pcmLevel = 128 + lookup(input And &HF)
ElseIf Int16.Parse(pcmLevel) + lookup(input And &HF) > 127 Then
pcmLevel = -129 + lookup(input And &HF)
Else
pcmLevel += lookup(input And &HF)
End If
data.Add(pcmLevel)
' exit when currentSize >= cry.Size
size += 2
If size >= CryToLoad.Size Then
Exit While
End If
alignment -= 1
End While
CryToLoad.Data = data.ToArray()
' bytes needed to recompress
CryToLoad.Size = offtrack / 2 'offtrack - start
End If
Return CryToLoad
End Function
Public Function GetCryImage(cry As Cry) As Bitmap
Dim cryImage As Bitmap
If GetString(AppPath & "GBAPGESettings.ini", "Settings", "DisableCryImage", "0") = "1" Then
cryImage = New Bitmap(128, 128)
Else
cryImage = New Bitmap(cry.Data.Length, 128)
Using g = Graphics.FromImage(cryImage)
For i As Integer = 1 To cry.Data.Length - 1
g.DrawLine(Pens.Green, i - 1, 64 + cry.Data(i - 1), i, 64 + cry.Data(i))
Next
End Using
End If
Return cryImage
End Function
Public Sub PlayCry(cry As Cry)
' TODO: we could do this in another thread :O
If cry.Offset = 0 Then
Exit Sub
End If
Using stream = New MemoryStream()
' "save" the cry to a memorystream
Using writer As BinaryWriter = New BinaryWriter(stream, Encoding.ASCII, True)
' RIFF header
writer.Write(Encoding.ASCII.GetBytes("RIFF"))
writer.Write(0)
writer.Write(Encoding.ASCII.GetBytes("WAVE"))
' fmt chunk
writer.Write(Encoding.ASCII.GetBytes("fmt "))
writer.Write(16)
writer.Write(CUShort(1))
writer.Write(CUShort(1))
writer.Write(cry.SampleRate)
writer.Write(cry.SampleRate)
writer.Write(CUShort(1))
writer.Write(CUShort(8))
' data chunk
writer.Write(Encoding.ASCII.GetBytes("data"))
writer.Write(cry.Data.Length)
For Each sample As SByte In cry.Data
writer.Write(CByte(sample + &H80))
Next
' fix header
writer.Seek(4, SeekOrigin.Begin)
writer.Write(CInt(writer.BaseStream.Length) - 8)
End Using
' play it via a soundplayer
stream.Seek(0L, SeekOrigin.Begin)
Using player = New SoundPlayer(stream)
player.Load()
player.Play()
End Using
End Using
End Sub
Public Sub ExportCry(filename As String, cry As Cry)
If cry.Offset = 0 Then
Return
End If
' http://www-mmsp.ece.mcgill.ca/documents/audioformats/wave/wave.html
' http://soundfile.sapp.org/doc/WaveFormat/
Using writer = New BinaryWriter(File.Create(filename))
' RIFF header
writer.Write(Encoding.ASCII.GetBytes("RIFF"))
' file ID
writer.Write(0)
' file size placeholder
writer.Write(Encoding.ASCII.GetBytes("WAVE"))
' format
' fmt chunk
writer.Write(Encoding.ASCII.GetBytes("fmt "))
' chunk ID
writer.Write(16)
' chunk size, 16 for PCM
writer.Write(CUShort(1))
' format: 1 = wave_format_pcm
writer.Write(CUShort(1))
' channel count
writer.Write(cry.SampleRate)
' sample rate
' * 1 * 8 / 8
writer.Write(cry.SampleRate)
' SampleRate * NumChannels * BitsPerSample/8
' * 8 / 8
writer.Write(CUShort(1))
' NumChannels * BitsPerSample/8
writer.Write(CUShort(8))
' bits per sample
' data chunk
writer.Write(Encoding.ASCII.GetBytes("data"))
' chunk ID
writer.Write(cry.Data.Length)
' chunk size
For Each sample As SByte In cry.Data
writer.Write(CByte(sample + &H80))
Next
' wave PCM is unsigned unlike GBA PCM which is
' fix header
writer.Seek(4, SeekOrigin.Begin)
writer.Write(CInt(writer.BaseStream.Length) - 8)
End Using
End Sub
Public Function ImportCry(filename As String, CryToLoad As Cry) As Cry
'If Cry.Offset = 0 Then
' Return
'End If
' load a wave file
Using reader = New BinaryReader(File.OpenRead(filename))
' read RIFF header
If reader.ReadUInt32() <> &H46464952 Then
Throw New Exception("This is not a WAVE file!")
End If
If reader.ReadInt32() + 8 <> reader.BaseStream.Length Then
Throw New Exception("Invalid file length!")
End If
If reader.ReadUInt32() <> &H45564157 Then
Throw New Exception("This is not a WAVE file!")
End If
' read fmt chunk
If reader.ReadUInt32() <> &H20746D66 Then
Throw New Exception("Expected fmt chunk!")
End If
If reader.ReadInt32() <> 16 Then
Throw New Exception("Invalid fmt chunk!")
End If
If reader.ReadInt16() <> 1 Then
' only PCM format allowed
Throw New Exception("Cry must be in PCM format!")
End If
If reader.ReadInt16() <> 1 Then
' only 1 channel allowed
Throw New Exception("Cry cannot have more than one channel!")
End If
CryToLoad.SampleRate = reader.ReadInt32()
If reader.ReadInt32() <> CryToLoad.SampleRate Then
Throw New Exception("Invalid fmt chunk!")
End If
reader.ReadUInt16()
Dim bitsPerSample = reader.ReadUInt16()
If bitsPerSample <> 8 Then
' for now, only 8 bit PCM data
Throw New Exception("Cries must be 8-bit WAVE files! Got {bitsPerSample}-bit instead.")
End If
' data chunk
If reader.ReadUInt32() <> &H61746164 Then
Throw New Exception("Expected data chunk!!")
End If
Dim dataSize = reader.ReadInt32()
CryToLoad.Data = New SByte(dataSize - 1) {}
For i As Integer = 0 To dataSize - 1
' read 8-bit unsigned PCM and convert to GBA signed form
CryToLoad.Data(i) = CSByte(reader.ReadByte() - 128)
Next
End Using
' resetting some other properties just in case
CryToLoad.Looped = False
CryToLoad.LoopStart = 0
Return CryToLoad
End Function
'Public Function SaveCry(crytosave As Cry, cryTable As Integer) As Boolean
' If crytosave.Offset = 0 Then
' Return False
' End If
' 'var lookup = new byte[] { 0x0, 0x1, 0x4, 0x9, 0x10, 0x19, 0x24, 0x31, 0xC0, 0xCF, 0xDC, 0xE7, 0xF0, 0xF7, 0xFC, 0xFF };
' Dim lookup = New SByte() {0, 1, 4, 9, 16, 25,
' 36, 49, -64, -49, -36, -25,
' -16, -9, -4, -1}
' crytosave.Compressed = Pokemonedit.chkCompressed1.Checked
' ' copy cry data to be written
' Dim data = New List(Of Byte)()
' If crytosave.Compressed Then
' 'MsgBox("This should not be enabled!")
' 'End
' ' data is compressed in blocks of 1 + 0x20 bytes at a time
' ' first byte is normal signed PCM data
' ' following 0x20 bytes are compressed based on previous value
' ' (for a value not in lookup table, closest value will be chosen instead)
' 'Console.WriteLine("compressed");
' ' each block has 0x40 samples
' Dim blockCount = crytosave.Data.Length / &H40
' If crytosave.Data.Length Mod &H40 > 0 Then
' blockCount += 1
' End If
' ' truncates the length of the last block
' ' so we don't waste space
' Dim lastBlockSize = crytosave.Data.Length - crytosave.Data.Length / &H40 * &H40
' If lastBlockSize = 0 Then
' lastBlockSize = &H21
' Else
' lastBlockSize = 1 + (lastBlockSize / 2) + (If(lastBlockSize Mod 2 = 0, 0, 1))
' End If
' Dim blocks = New Byte(blockCount - 1)() {}
' For n As Integer = 0 To blockCount - 1
' ' create new block
' If n < blockCount - 1 Then
' blocks(n) = New Byte(32) {}
' Else
' blocks(n) = New Byte(lastBlockSize - 1) {}
' End If
' Dim i As Integer = n * &H40
' Dim k As Integer = 0
' If i < crytosave.Data.Length Then
' ' set first value
' blocks(n)(k) = BitConverter.GetBytes(crytosave.Data(i))(0)
' End If
' k = k + 1
' Dim pcm As SByte
' If i < crytosave.Data.Length Then
' pcm = crytosave.Data(i)
' End If
' i = i + 1
' Dim j As Integer = 1
' While j < &H40 And i < crytosave.Data.Length
' ' get current sample
' Dim sample As SByte = crytosave.Data(i)
' i = i + 1
' ' difference between previous sample and this
' Dim diff As Integer = sample - pcm
' ' check for a perfect match in lookup table
' Dim lookupI = -1
' For x As Integer = 0 To 15
' If lookup(x) = diff And (pcm + diff <= 127) And (pcm + diff >= -128) Then
' lookupI = x
' Exit For
' End If
' Next
' ' search for the closest match in the table
' If lookupI = -1 Then
' Dim bestDiff As Integer = 255
' For x As Integer = 0 To 15
' If Math.Abs(CInt(lookup(x)) - diff) < bestDiff And (pcm + lookup(x) <= 127) And (pcm + lookup(x) >= -128) Then
' lookupI = x
' bestDiff = Math.Abs(lookup(x) - diff)
' End If
' Next
' End If
' ' set value in block
' ' on an odd value, increase position in block
' If j Mod 2 = 0 Then
' blocks(n)(k) = blocks(n)(k) Or CByte(lookupI << 4)
' Else
' blocks(n)(k) = blocks(n)(k) Or CByte(lookupI)
' k = k + 1
' End If
' ' set previous
' pcm = sample
' j += 1
' End While
' Next
' For n As Integer = 0 To blockCount - 1
' data.AddRange(blocks(n))
' Next
' Else
' ' uncompressed, copy directly to data
' 'Console.WriteLine("uncompressed");
' For Each s As SByte In crytosave.Data
' data.Add(CByte(s And &HFF))
' Next
' End If
' ' determine if cry requires repointing
' If crytosave.Size < data.Count Then
' Dim result As DialogResult = MessageBox.Show("The Cry will be written to free space and the pointer will be repointed. Would you like to do that?",
' "Repoint?",
' MessageBoxButtons.YesNo)
' If (result = DialogResult.Yes) Then
' Dim result2 As DialogResult = MessageBox.Show("Fill the old cry with free space?",
' "Delete old cry?",
' MessageBoxButtons.YesNo)
' If (result2 = DialogResult.Yes) Then
' WriteHEX(LoadedROM, crytosave.Offset, MakeFreeSpaceString(crytosave.Size + 16))
' End If
' ' set new cry offset
' crytosave.Offset = SearchFreeSpaceFourAligned(LoadedROM, &HFF, data.Count, "&H" & GetString(GetINIFileLocation(), header, "StartSearchingForSpaceOffset", "800000"))
' Else
' Return False
' End If
' End If
' ' write cry
' WriteHEX(LoadedROM, crytosave.Offset, ReverseHEX(VB.Right("0000" & CUShort(If(crytosave.Compressed, 1, 0)), 4)))
' WriteHEX(LoadedROM, crytosave.Offset + 2, ReverseHEX(VB.Right("0000" & CUShort(If(crytosave.Looped, &H4000, 0)), 4)))
' WriteHEX(LoadedROM, crytosave.Offset + 4, ReverseHEX(VB.Right("00000000" & (crytosave.SampleRate << 10), 8)))
' WriteHEX(LoadedROM, crytosave.Offset + 8, ReverseHEX(VB.Right("00000000" & (crytosave.LoopStart), 8)))
' WriteHEX(LoadedROM, crytosave.Offset + 12, ReverseHEX(VB.Right("00000000" & (crytosave.Data.Length - 1), 8)))
' 'WriteHEX(LoadedROM, crytosave.Offset, ReverseHEX(VB.Right("0000" & CUShort(If(crytosave.Compressed, 1, 0)), 4)))
' 'WriteHEX(LoadedROM, crytosave.Offset + 2, ReverseHEX(VB.Right("0000" & CUShort(If(crytosave.Looped, &H4000, 0)), 4)))
' 'WriteHEX(LoadedROM, crytosave.Offset + 4, ReverseHEX(VB.Right("00000000" & (crytosave.SampleRate << 10), 8)))
' 'WriteHEX(LoadedROM, crytosave.Offset + 8, ReverseHEX(VB.Right("00000000" & (crytosave.LoopStart), 8)))
' 'WriteHEX(LoadedROM, crytosave.Offset + 12, ReverseHEX(VB.Right("00000000" & (crytosave.Data.Length - 1), 8)))
' Dim tempbuff As String = ByteArrayToHexString(data.ToArray)
' WriteHEX(LoadedROM, crytosave.Offset + 16, tempbuff)
' ' write cry table entry
' 'WriteHEX(LoadedROM, cryTable + (crytosave.Index * 12), ReverseHEX(If(crytosave.Compressed, "00003C20", "00003C00")))
' 'WriteHEX(LoadedROM, cryTable + (crytosave.Index * 12) + 4, ReverseHEX(VB.Right("00000000" & Hex(crytosave.Offset), 8)))
' 'WriteHEX(LoadedROM, cryTable + (crytosave.Index * 12) + 8, "FF00FF")
' 'rom.WriteUInt16(CUShort(If(Cry.Compressed, 1, 0)))
' 'rom.WriteUInt16(CUShort(If(Cry.Looped, &H4000, 0)))
' 'rom.WriteInt32(Cry.SampleRate << 10)
' 'rom.WriteInt32(Cry.LoopStart)
' 'rom.WriteInt32(Cry.Data.Length - 1)
' 'rom.WriteBytes(data.ToArray())
' '' write cry table entry
' 'rom.Seek(cryTable + Cry.Index * 12)
' 'rom.WriteUInt32(If(Cry.Compressed, &H3C20UI, &H3C00UI))
' 'rom.WritePointer(Cry.Offset)
' 'rom.WriteUInt32(&HFF00FFUI)
' '' write growl table entry
' 'rom.Seek(growlTable + Cry.Index * 12)
' 'rom.WriteUInt32(If(Cry.Compressed, &H3C30UI, &H3C00UI))
' '' !!! not sure if 00 should be used for uncompressed
' 'rom.WritePointer(Cry.Offset)
' 'rom.WriteUInt32(&HFF00FFUI)
' Return True
'End Function
Public Function SaveCryNoPrompt(crytosave As Cry, cryTable As Integer, growlTable As Integer) As Boolean
'If crytosave.Offset = 0 Then
'Return False
'End If
'var lookup = new byte[] { 0x0, 0x1, 0x4, 0x9, 0x10, 0x19, 0x24, 0x31, 0xC0, 0xCF, 0xDC, 0xE7, 0xF0, 0xF7, 0xFC, 0xFF };
Dim lookup = New SByte() {0, 1, 4, 9, 16, 25,
36, 49, -64, -49, -36, -25,
-16, -9, -4, -1}
crytosave.Compressed = Pokemonedit.imptCompChk.Checked
' copy cry data to be written
Dim data = New List(Of Byte)()
If crytosave.Compressed Then
'MsgBox("This should not be enabled!")
'End
' data is compressed in blocks of 1 + 0x20 bytes at a time
' first byte is normal signed PCM data
' following 0x20 bytes are compressed based on previous value
' (for a value not in lookup table, closest value will be chosen instead)
'Console.WriteLine("compressed");
' each block has 0x40 samples
Dim blockCount = crytosave.Data.Length / &H40
If crytosave.Data.Length Mod &H40 > 0 Then
blockCount += 1
End If
' truncates the length of the last block
' so we don't waste space
Dim lastBlockSize = crytosave.Data.Length - crytosave.Data.Length / &H40 * &H40
If lastBlockSize = 0 Then
lastBlockSize = &H21
Else
lastBlockSize = 1 + (lastBlockSize / 2) + (If(lastBlockSize Mod 2 = 0, 0, 1))
End If
Dim blocks = New Byte(blockCount - 1)() {}
For n As Integer = 0 To blockCount - 1
' create new block
If n < blockCount - 1 Then
blocks(n) = New Byte(32) {}
Else
blocks(n) = New Byte(lastBlockSize - 1) {} ' - Not "- 1"
End If
Dim i As Integer = n * &H40
Dim k As Integer = 0
If i < crytosave.Data.Length Then
' set first value
blocks(n)(k) = BitConverter.GetBytes(crytosave.Data(i))(0)
End If
k = k + 1
Dim pcm As SByte
If i < crytosave.Data.Length Then
pcm = crytosave.Data(i)
End If
i = i + 1
Dim j As Integer = 1
While j < &H40 And i < crytosave.Data.Length
' get current sample
Dim sample As SByte = crytosave.Data(i)
i = i + 1
' difference between previous sample and this
Dim diff As Integer = Int16.Parse(sample) - Int16.Parse(pcm)
Dim lookupI = -1
' search for the closest match in the table
Dim bestDiff As Integer = 255
For x As Integer = 0 To 15
'If ((Math.Abs(CInt(lookup(x)) - diff) < bestDiff) Or (lookup(x) = diff)) And Not ((lookup(x) < 0 And diff > 0) Or (lookup(x) > 0 And diff < 0)) Then ' Good or Perfect Difference
If ((Math.Abs(CInt(lookup(x)) - diff) < bestDiff) Or (lookup(x) = diff)) Then ' Good or Perfect Difference
'Check for Overflow/Underflow to prevent crackling
If (Int16.Parse(pcm) + lookup(x) < 127) Then
If (Int16.Parse(pcm) + lookup(x) > -128) Then
lookupI = x
bestDiff = Math.Abs(lookup(x) - diff)
Else
End If
Else
End If
End If
Next
' set value in block
' on an odd value, increase position in block
If j Mod 2 = 0 Then
blocks(n)(k) = blocks(n)(k) Or CByte(lookupI << 4)
Else
blocks(n)(k) = blocks(n)(k) Or CByte(lookupI)
k = k + 1
End If
' set previous
pcm = pcm + lookup(lookupI)
j += 1
End While
Next
For n As Integer = 0 To blockCount - 1
data.AddRange(blocks(n))
Next
Else
' uncompressed, copy directly to data
'Console.WriteLine("uncompressed");
For Each s As SByte In crytosave.Data
data.Add(CByte(s And &HFF))
Next
End If
' set new cry offset
crytosave.Offset = SearchFreeSpaceFourAligned(LoadedROM, &HFF, data.Count + 16, "&H" & GetString(GetINIFileLocation(), header, "StartSearchingForSpaceOffset", "800000"))
' write cry
WriteHEX(LoadedROM, crytosave.Offset, ReverseHEX(VB.Right("0000" & CUShort(If(crytosave.Compressed, 1, 0)), 4)))
WriteHEX(LoadedROM, crytosave.Offset + 2, ReverseHEX(VB.Right("0000" & CUShort(If(crytosave.Looped, &H4000, 0)), 4)))
WriteHEX(LoadedROM, crytosave.Offset + 4, ReverseHEX(VB.Right("00000000" & Hex(crytosave.SampleRate << 10), 8)))
WriteHEX(LoadedROM, crytosave.Offset + 8, ReverseHEX(VB.Right("00000000" & Hex(crytosave.LoopStart), 8)))
WriteHEX(LoadedROM, crytosave.Offset + 12, ReverseHEX(VB.Right("00000000" & Hex(crytosave.Data.Length - 1), 8)))
Dim tempbuff As String = ByteArrayToHexString(data.ToArray)
WriteHEX(LoadedROM, crytosave.Offset + 16, tempbuff)
' write cry table entry
WriteHEX(LoadedROM, cryTable + ((crytosave.Index - 1) * 12), ReverseHEX(If(crytosave.Compressed, "00003C20", "00003C00")))
WriteHEX(LoadedROM, cryTable + ((crytosave.Index - 1) * 12) + 4, ReverseHEX(VB.Right("00000000" & Hex(crytosave.Offset + &H8000000), 8)))
WriteHEX(LoadedROM, cryTable + ((crytosave.Index - 1) * 12) + 8, "FF00FF")
WriteHEX(LoadedROM, growlTable + ((crytosave.Index - 1) * 12), ReverseHEX(If(crytosave.Compressed, "00003C30", "00003C00")))
WriteHEX(LoadedROM, growlTable + ((crytosave.Index - 1) * 12) + 4, ReverseHEX(VB.Right("00000000" & Hex(crytosave.Offset + &H8000000), 8)))
WriteHEX(LoadedROM, growlTable + ((crytosave.Index - 1) * 12) + 8, "FF00FF")
If crytosave.Index > 276 Then
Dim offset As Integer = Int32.Parse((GetString(GetINIFileLocation(), header, "CryConversionTable", "")), System.Globalization.NumberStyles.HexNumber)
WriteHEX(LoadedROM, ((offset)) + ((crytosave.Index - 277) * 2), ReverseHEX(VB.Right("0000" & Hex(crytosave.Index - 1), 4)))
End If
Return True
End Function
End Module