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 - Maki

Pages: [1] 2 3 ... 21
1
You are looking for so-called "code caves". Quick scan for memory in runtime yelds these adresses of at least 64 bytes of memory padding that you can use for code injection:

Code: [Select]
00400298
00403A30
00469548
004823FB
00484C23
00487384
0048A25C
0048A2FE
0048E4A9
00491267
004913CF
004B3AD7
004B5761
004CAB0A
00505E51
00506255
0050A713
0056AAF3
00667B10
00670E38
006757F8
006E5F39
008454C1
00B68783

These are applicable for FF8 2000 PC release with 1.1 patch. There's no big difference in Steam version for that.
In future you can use Cheat Engine>Memory View>Tools>Scan for code caves


As for resetting the counter, I'm a little less sure of where to put it but was thinking the battle results screen as even when escaping that screen tends to come up. Does anyone know where that section starts from?

The easiest what comes to my mind is checking if engine_state == 8 (this is battle mode). If not, then reset counter, if yes, then ignore. Anyway, here are the main function to note:
FFBattleInitSystem (called from FFModuleHandler and FFBattleTransitionModule)- it's at 0047CE00 (0007CE00). More specifically:

Code: [Select]
FFBattleInitSystem+1E   66 83 3D C6 8F CD 01 08                 cmp     _StateGlobal, 8where _stateGlobal (global variable) is at 01CD8FC6 in .data in-memory

There's also:
FFBattleExitSystem called from FFModuleHandler and FFBattleTransitionModule that sets previous renderer screen-space and is located at:
0x0047CEE0 (0x0007CEE0)

@edit
About the R/W, it's true, but only if you need to store some local. Here are some 64 bytes regions with R/W: (but use them rather for storing what you need instead of code)
Code: [Select]
00B6D0A8 <- I recommend this one, it's section between imports for PE and strings that are allocated on 256 bytes
00B6D1B2
00B6D2B7
00B6D3C1
00B6D4BE
00B6D5C4
00B6D6C7
00B76918
00B7CDA8
00B7CF13
00B7D10B
00B7D18B
00B7D20B
00B7D2A7
00B7D507
00B7D6A7
00B7D713
00B7D90B
00B7D98B
00B7DA0B
00B7DC23
00B7DE1B
00B7DE9B
00B7DF1B
00B8A53B
00B8B3A7
00B8C1F3
00B8C2F7
00B8C3FB
00B8C514
00B8C618
00B8C71C
00B8C832
00B8C936
00B8CA3A
00B8CB53
00B8CC57
00B8CD5B
00B8CE73
00B8CF77
00B8D07B
00B8D192
00B8D296
00B8D39A
00B8DCCA
00B96EE4
00B976AF
00B97885
00B97A05
00B97B85
00B97DA4
00B97F25
00B980A5
00B98225
00B98563
00B986E3
00B9888E
00B98A0F
00B98B8F
00B98D0F
00B98E8F
00B9A50D

2
It's live!
https://github.com/MaKiPL/ffvi_flb/releases/latest

Colours are correct now with dynamic replace. Tested with one-sprite package, first replace, last replace, n replace and in-game replace. Everything looks great. Have fun!

3
Great news!
I managed to code fully working replace with sizing (you can import high resolution images, I tested replacing 512x512>1024x1024 and 512x256> 128x64 and it works really great! Although the game engine doesn't sctretch the assets (at least the ones I tested). Anyway, here's current github page:
https://github.com/MaKiPL/ffvi_flb
it's still WIP, there are some color issues with dynamic replace (dynamic is when you change .PNG resolution) and I still haven't tested it on one sprite only FLB files.

I have a load of work at job so I'll try to do it asap

4
copy of game? Only for testing as I'm not sure the pointers are enough for modifying the file. Anyway, here's the entry version of the tool that does unpacking transparent .PNG graphics from .FLB, do not click on replace, it does nothing atm. I'm sharing this in this non-completed state as you may start working on the graphics now while I'll be working out the repacking:

Compiled binary + source code so far:
https://www.dropbox.com/s/iyi5nuheqth52kb/FLB_tool.7z?dl=0
Just go to bin>release and you'll find exe there

5
That's unusual, but if that's the author intention then ok, send it over PM.
File format so far:
Code: [Select]
char[8] FLBD0101;
uint IMCHpointer;
uint unk;
padding[8]; //?
uint UnknownSHCHpointer; //0x28 + this
uint UnknownSPCHpointer; //0x28 + this
uint UnknownBTCHpointer; //0x28 + this
uint UnknownANCH0pointer; //0x28 + this
IMCH imch;

IMCH:
Code: [Select]
char[4] IMCH
uint IMCHsize; //including this + IMCH header
uint CountOfFrames; //This is global count of pointers to graphics;sprites;frames in file. It means one FLB can contain many graphics
uint SpritePointer[CountOfFrames]; //first one usually points to 0x00, so just: IMCHpointer+IMCHsize+pointer;

SpriteData:
Code: [Select]
byte[20] unknown_maybeChecksum?;
uint Unknown;
ushort width;
ushort height;
TEXTUREdata;

UPDATE:
Oh, ok. I got it! Updated the structure

Example summon_00f_bg1_full.flb is 256x512 and raw texture data is 524288 bytes;
256x512 is 131072; 393216 is dividable by:
Code: [Select]
Size:   1
Size:   2
Size:   3
Size:   4 <--
Size:   6
Size:   8
Size:   12
Size:   16
Size:   24
Size:   32
Size:   48
Size:   64
Size:   96
Size:   128
Size:   192

131072 * 4 = 524288;
So this is for sure 32 BPP data, therefore:

Are these colors ok?


Reimporting:
As far as I see:
1. Inject upgraded/upscaled texture data
2. Change width/height
3. Tweak SHCH; SPCH; BTCH and ANCH0 pointers
4. Tweak IMCH pointers to texture data that got changed due to different imageSize after the pointer to changed textureData
5. Well, looks like that's all. :-)

UPDATE2:
Diablos looks great! (ARGB -> BGRA/ABGR)

6
Please provide any information you have and a sample file.

7
Quote
This looks awesome Maki, do you have a tutorial on how to set it up, do you need to download unity etc
Oh right, sorry. I'll make sure to write the tutorial to set-up everything ASAP

Quote
porting FF8 to PS4 aswell, via Custom UNITY engine?
So... I'm working in gamedev industry and have access to official PS4+XOne SDK*, but even with that it's not so easy. For Unity you need to have full commercial license. It's better for XNA however, as you need only the target file. Anyway, everything's possible.

*but please do not ask me for anything about it. :(

8
This is true act of bored person:
OpenVIII - the FF8 engine set:
https://www.dropbox.com/s/069wd7lcvopjf0h/FF8.7z?dl=0

Just two implementations of FF8 engine that works ONLY on real VIII files meaning you wouldn't even run it without Steam release of VIII or slight code change.

In the package you will find:
OpenVIII - This is Unity project, that provides:
  • real-time battle 3D rendering with textures
  • basic field rendering with camera setup
  • all LZSS, field archive and whole core

FF8 - This is Monogame project, that provides:
  • real-time battle 3D rendering with textures that renders face one-by-one considering the CLUT (closest to original fan-made battle stage rendering ever made)
  • basic field rendering
  • real DirectMidi support for direct DLS and SGT music
  • Movie player (unfortunately not Bink wrapping, but casual MPEG4 without sound)
  • all LZSS, field archive and whole core

Use it to learn, use it for your own projects, use it to listen to music or view 1:1 stages with FPS camera, whatever. I simply don't care.

Tutorial:
Before you proceed with anything make sure you have Final Fantasy VIII steam version installed (or 2000 PC version if you can do basic coding)


FF8 - XNA/MonoGame:

1. You may need to install MonoGame for VisualStudio. You can do it without any problems at: http://www.monogame.net/downloads/ ; Just make sure to download DEVELOPMENT build for Visual Studio instead of official releases (they are quite outdated)
2. After grabbing MonoGame you'll be able to open Visual Studio 2015 (minimum) project without any problems. Just open FF8.sln with Visual Studio
3. Open Game1.cs- this is entry-point class. You can uncomment line 26 at init_debugger_Audio.DEBUG(); to enable DirectMusic
4. Open Memory.cs and take a look at lines 37 and 38. You'll understand the drill. Set the path there to your lang-en catalogue of FF8 or change it to e.g. lang-fr, doesn't matter, files should be there. Make sure path ends with '\' (lazy programmer I am)
5. DONE! You'll enter automatically into field mode. Use F keys to change modes:
F2 - change module to battle and set to next stage
F3 - Next music
F4 - change module to field and set to next field
F5 - same as above but gets back to previous field ID
Battle stage:
Movement mouse; WSAD translation
Quitting:
ALT+F4 ;_;

9
Python code for getting 'objects' element, also contains structure data:

Code: [Select]
import sys
import struct

#CONFIG
filePath = sys.argv[1]
#END OF CONFIG

print(filePath)
#XmbDocument
f = open(filePath, 'rb')
xmb2 = f.read(4)
eof = struct.unpack('L', f.read(4))[0]
flags = struct.unpack('H', f.read(2))[0]
version = struct.unpack('H', f.read(2))[0]
rootElement = struct.unpack('L', f.read(4))[0]
f.seek(rootElement-4,1) #xmbDocument is casted now to XmbElement

#XmbElement
xmb2Element_elementStartOffset = struct.unpack('L', f.read(4))[0] #v6
xmb2Element_attributeStartOffset = struct.unpack('L', f.read(4))[0]
xmb2Element_elementCount = struct.unpack('H', f.read(2))[0]
xmb2Element_attributeCount = struct.unpack('H', f.read(2))[0] >> 8

f.seek(-12,1) #going back to XMB2Element root
AbsoluteXmb2ElementRoot = f.tell() # &v3->elementStartOffset_
IndexPointer = 0 #v4
SignedPointer = AbsoluteXmb2ElementRoot + 4 * IndexPointer + xmb2Element_elementStartOffset
f.seek(SignedPointer, 0)
SignedPointerValue = struct.unpack('i', f.read(4))[0]
v7 = AbsoluteXmb2ElementRoot + (4*IndexPointer) + xmb2Element_elementStartOffset + SignedPointerValue
#(char *)(v7 + *(_DWORD *)(v7 + 4) + 4i64);
v8Pointer = v7 + 4
f.seek(v8Pointer, 0)
v8PointerValue = struct.unpack('I', f.read(4))[0]
_ = v7 + v8PointerValue + 4
f.seek(_,0)
#v9 = &v8[*(_DWORD *)v8];
v8 = struct.unpack('i', f.read(4))[0]
f.seek(-4,1)
v8Pointer = f.tell()
v9 = v8Pointer + v8
f.seek(v9, 0)
v9Pt = struct.unpack('B', f.read(1))[0]
if v9Pt == 1:
f.seek(v9+5, 0)
v10Pt = struct.unpack('I', f.read(4))[0]
v10 = v9+v10Pt+5
f.seek(v10,0)
objectName = f.read().split('\0')[0]
print('Index: ' + str(IndexPointer) + ': ' + objectName)

10
Just a quick hint- FFXV_s.exe base is dynamic, therefore patch:
Code: [Select]
ffxv_s.exe:0x1EE = 0x20 (replacing 0x60, 2nd bit from 1 to 0)
this will disable ASLR and base image on 0x140000000

any further notes I'll write here will consider 0x140000000 as the base instead of 0x00007FF*

If you're using IDA make sure to rebase the database last time by Edit>Segment>Rebase, for CE or Olly it doesn't matter, anyway I'll try to post relative addresses like ffxv_s.exe+0xFFFF like in CE style

Okay, about XML20 (exml):
Xmb2document:
Code: [Select]
00000000 identifier dd ?
00000004 fileSize dd ?
00000008 flags dw ?
0000000A version dw ?
0000000C rootElementOffset dd ? <-- relative to root

Getting elements (useful for offset strawberries):
Code: [Select]
SQEX::Luminous::Xml::Xmb2Element::GetElementByName(Xmb2Element el, char* name);example:
000000016459061C SQEX::Luminous::Xml::Xmb2Element <elementStartOffset_: 0B44h, attributeStartOffset_: 0F58h, elementCount: 1, attribCount: 1h>

int64 i = 0;
var v7 = &xmb->elementStartOffset + 4* i + xmb->elementStartOffset + *((xmb->elementStartOffset)+&xmb->elementStartOffset)
Let's simplify it: we just jump to relative pointer of i * 4 of pointer address of XMB document + element start offset, like this:
Code: [Select]
uint64 pointer = XMBdocument + elementStartOffset + i*4;
uint64 v7 = pointer + *(pointer);

Now the unknown pointer:
char* v8 = v7 + (*(v7 + 4)+4);
if v8 is not null, then treat as array of objects:

v10 = v9 + *(v9+5) + 5

UPDATE2:
The abstraction level of everything here is so high... struct with struct with struct, that's not assembler-level friendly.

UPDATE3:
initialize1.exml:
Code: [Select]
0: reference
1: entities_.common_textures_list
2: entities_.initialize1_list
3: entities_.system_no_autoload
4: entities_
5: hasTransform_
6: bool
7: position_
8: float4
9: rotation_
10: scaling_
11: float
12: canManipulate_
13: sourcePath_
14: common/initialize1.ebex
15: string
16: name_
17: dff7c814-9313-45a9-b8fd-5fc7ca670db7
18: isTemplateTraySourceReference_
19: isShared_
20: startupLoad_
21: object
22: initialize1
23: SQEX.Ebony.Framework.Entity.EntityPackage
24:
25: filePath_
26: textures/ebony_required_textures.txt
27: isAutoLoad_
28: common_textures_list
29: Black.Entity.Data.EarcResourceList
30: common/initialize1_list.txt
31: initialize1_list
32: common/system_no_autoload.txt
33: system_no_autoload
34: objects
35: package

UPDATE4:
Looks like it's raw data that is treated via struct. Currently it looks like the pointers and attribute+element count is stored in the middle of the file.
ai/commonai/commontpslibrary.exml ->
debug::63140000 = XMB2
debug::6314016C = XMBDocument

Looks like EXML contains many XMBDocuments

11
I just got an e-mail from "Haggy" with an amazing report- due to mistake SquareEnix uploaded debug build of FFXV with PDB !!!
Whole build with pseudocode is available to download on the bay, just search for "Final Fantasy XV Debug Symbols".

UPDATE:
Full debug information with even troubleshooting is there xD



Important functions (changed argument names for clarity):
Code: [Select]
void ** SQEX::Luminous::AssetManager::LmArcFileSystem::OpenFile (LmArcFileSystem *this, LmAssetID *i_id, LmEAssetLoadPriority priority)


File read:
SQEX::Luminous::AssetManager::LmArcFileSystem::ReadFile -> determines if compressed or not by LmArcInterface::FindAssetInfo ->


int64 SQEX::Luminous::AssetManager::LmArcFileSystem::ReadCompressed(LmArcFileSystem *this, FileSystemEntry *i_pFileEntry, ArcAssociation *i_pArchive /* this one is archive name in 80%*/, void *o_pAddress, unsigned int i_length, void **io_asyncHandle, LmEAssetLoadPriority priority, SQEX::Luminous::Core::IO::IFileDevice::FileAttribute attribute)

struct LmArcInterface::ArcAssociation (this is what we know so far despite being a copy-of AssetManager:LmAssetKey):

Code: [Select]
QWORD entry ; offset // It's in fact in code as LmArcCatalogShortEntry
DWORD arcMountIndex
BYTE UNK ; undefined
BYTE UNK ; undefined
BYTE UNK ; undefined
BYTE UNK ; undefined

LmArcCatalogShortEntry:
Code: [Select]
QWORD nameTypeHash    dq ?
QWORD dataStart
std::string name
std::string pAbsolutePath
DWORD originalSize
DWORD compressedSize
USHORT flags
BYTE localizeType
BYTE localizeLocale
SHORT encryptKey
BYTE UNK
BYTE UNK


Visual Studio works as expected:

12
General discussion / Re: Rinoa in Dissidia !
« on: 2018-07-18 20:05:30 »
Is Dissidia easy to rip? Wish to play with her model (nothing naughty!)

13
Quote
The images showcasing Cloud’s design, which have been shown during the Visual Works presentation are from the theme park ride at Universal Studios Japan, and not straight from Final Fantasy VII Remake.

14
General discussion / Re: Final Fantasy 8 in Unity?
« on: 2018-07-09 10:28:12 »
when you forget to clear object collections (and textures) when changing stages:

it produces actually very cool effects.

15
General discussion / Re: Final Fantasy 8 in Unity?
« on: 2018-07-06 08:24:57 »
World of Final Fantasy has fully modelled Balamb hall (with some 'artistic' addons):

extremely good for reference purpouses and floor texture

Vista is also there:


Textured in UE4 if I didn't mess up some materials (the model has changed text [translated english to rubbish made-up language] and logo is different):

16
I had similar issue when I used DgVoodoo interceptor for FF8 from 2000 when debugging with IDA. The fixed that worked for me was starting the game and not touching single button. Just click start/run app and completely leave any input. Also make sure to unplug any gamepads. They tend to have "priority" on input. Also take a look at device manager of you have some shady/broken virtual gamepad or input method. FF8 works on DirectInput and collects available input devices from OS.

17
Are you able to do the same but for DLS DirectMusic?

18
Got it working- I had an error in palette code. There are no Type 1 or type 2, everything is type 2.
When there's only 16 palettes and remaining 8 are null, then the palette pointer is not exceeding 8.
also skip rendering if pixel =0 because it's transparency driven. I'm missing mixing parameters/states

19
Mod organizer got release some times ago- looks like C# WPF application- and in fact it is. 64 bit build- free to download for everyone, even if you don't own FFXV directly from Steam. Mod organizer is not protected and you can easily decompile full source code via ILSpy including archive tool with .EARC builder algorithm including debug strings:
Code: [Select]
if (!File.Exists(temp_earc))
{
Console.WriteLine(temp_earc + " が出力されていない");
return -1;
}

UPDATE:
Nope, no archive building, everything it does is calling an exe in a thread to:
%REBLACK_ROOT%"), "luminous\\sdk\\tools\\Backend\\AssetConverterFramework\\BuildCoordinator\\bin\\tonberry.exe"


Code: [Select]
string fullName = Directory.GetParent(tonberry_FullPath).FullName;
string text = additional_args + " --force --protect --encrypt --server " + ebex + "@";
CommandProcess.Execute(tonberry_FullPath, text, out num, null, fullName, null, true);

20
Hello everyone! I'm trying to implement my own MIM+MAP algorithm, yet the wiki page is quiet chaotic. Myst6re's Deling source code helped a bit, yet I face some issues:

-When does exactly the stage is type 1 or type 2? Are there really two types? In Wiki and Deling source code we see that types are distinguishable by .MIM filesize, yet I wasn't really able to find 401408 bytes .MIM
Anyway, I treat every single field like a type2. However, there's something odd:
I took two different stages and tried to render it:


Please ignore black spots, I didn't implement blending.
Both the stages have EQUAL .MIM filesize; How do I know when to use palettes 0-8, or when 8-16?
What am I missing?

21
I managed to somewhat break the camera structure. I updated http://wiki.ffrtt.ru/index.php/FF8/FileFormat_X#Camera_data

Case study:
a0stg101.x - balamb plains:

0x5D8 - camera start [via code]
02 00 is skipped
08 00 is pointer to camera settings
20 00 is pointer to camera animation

Let's jump to camera animation as it's the most important part here.

We will end up at 0x32. This is sub-section. We will work with pointers relatively to this position.
You'll get a ushort for number of camera animations - in this example it's 7. [a0stg101.x have 7 sets, therefore 7*8 animations, but a0stg000 or a0stg001 don't remember but they have only one!, so 1*8 animations!]

Now, when the game starts and encounter is loaded it magically resolves which animation to use to show the enemy well. You can of course break at getting camera anim index code and change the register so the camera will present the enemy like it's T-rex showing only one mosquitoe (I don't remember that fly name on Balamb's plain).

So, we are at pointers indicator, the engine now:
EAX + ECX*2 + 02, where:
-EAX - absolute memory pointer to 07 00 or 08 00 as said above;
-ECX - the camera index that it got from from static memory (pointer to pointer to some packed binary values)
02 - size of numberOfAnimations

Let's jump to last animation now:
considering 07 00 in our file is now offset 0x00:
(7-1)*2+2 = 0xE //because 00 means first index, so 7th index is in fact 6*2

Now get ushort pointer at 0xE= 0x1F10;
We will get to 0x1F10. Engine now reads 8 pointers, like in this case first pointer is 08 00 and next is 48 00. Now it calculates it by pointer*2. So first pointer actually starts at 0x16, second at 0x48*2=0x90.

UPDATE3:
grab the useful breakpoint:
0x5035AB (Newest steam english).

UPDATE4:
Engine camera animation parsing at: sub_503C8F
checking for FFFF: 00503C7B:
cmp ax, 0xFFFF, where ax is *(019399E2) (cameraSet 1+ anim 5)

Operands are bit operated...

There:

22
Scripting and Reverse Engineering / Re: .SGT audio
« on: 2018-06-25 12:48:31 »
I though about other way of doing these things- why not just wrap DirectMusic?
I found this:
https://sourceforge.net/projects/directmidinet/?source=typ_redirect

It's a C# wrapper of C++ wrapper of original DirectXMusic

Sample bootstrap code:
Code: [Select]
            string pt = Memory.FF8DIR + "/../Music/dmusic/004s-run.sgt";
            CDirectMusic cdm = new CDirectMusic();
            cdm.Initialize();
            CDLSLoader loader = new CDLSLoader();
            loader.Initialize();
            CSegment segment;
            loader.LoadSegment(pt, out segment);
            CAPathPerformance path = new CAPathPerformance();
            path.Initialize(cdm, null, null, DMUS_APATH.DYNAMIC_3D, 128);
            CPortPerformance cport = new CPortPerformance();
            cport.Initialize(cdm, null, null);
            COutputPort outport = new COutputPort();
            outport.Initialize(cdm);

            uint dwPortCount = 0;
            INFOPORT infoport;
            do
                outport.GetPortInfo(++dwPortCount, out infoport);
            while (( infoport.dwFlags & DMUS_PC.SOFTWARESYNTH)==0);

            outport.SetPortParams(0, 0, 0, SET.REVERB | SET.CHORUS, 44100);
            outport.ActivatePort(infoport);

            cport.AddPort(outport, 0, 1);

            segment.Download(cport);
            cport.PlaySegment(segment);

I need to find the way to put .DLS in it, as the audio lacks some instruments, but it plays so great at another thread*

*looks like I need to make it FIXED as the memory relocation either kills the DirectMusic or whole application due to memory access violation
**Looks like the memory is moving only when reference pointer is nulled. Just make sure to set all available DirectMusic members as static and whole class as static to pin them.


Code for DLS support:
Code: [Select]
string pt = Memory.FF8DIR + "/../Music/dmusic/013s-battle2.sgt";
            cdm = new CDirectMusic();
            cdm.Initialize();
            loader = new CDLSLoader();
            loader.Initialize();
            loader.LoadSegment(pt, out segment);
            ccollection = new CCollection();
            loader.LoadDLS(Memory.FF8DIR + "/../Music/dmusic/FF8.dls",out ccollection );
            uint dwInstrumentIndex = 0;
            INSTRUMENTINFO iInfo;
            while (ccollection.EnumInstrument(++dwInstrumentIndex, out iInfo) == S_OK)
            {
                Debug.WriteLine(iInfo.szInstName);
            }

            path = new CAPathPerformance();
            path.Initialize(cdm, null, null, DMUS_APATH.DYNAMIC_3D, 128);
            cport = new CPortPerformance();
            cport.Initialize(cdm, null, null);
            outport = new COutputPort();
            outport.Initialize(cdm);

            uint dwPortCount = 0;
            INFOPORT infoport;
            do
                outport.GetPortInfo(++dwPortCount, out infoport);
            while ((infoport.dwFlags & DMUS_PC.SOFTWARESYNTH) == 0);

            outport.SetPortParams(0, 0, 0, SET.REVERB | SET.CHORUS, 44100);
            outport.ActivatePort(infoport);

            cport.AddPort(outport, 0, 1);

            for (int i = 0; i < dwInstrumentIndex; i++)
            {
                ccollection.GetInstrument(out instrument, i);
                outport.DownloadInstrument(instrument);
            }


            outport.DownloadInstrument(instrument);
            segment.Download(cport);
            //GCHandle.Alloc(cdm, GCHandleType.Pinned);
            //GCHandle.Alloc(loader, GCHandleType.Pinned);
            //GCHandle.Alloc(segment, GCHandleType.Pinned);
            //GCHandle.Alloc(path, GCHandleType.Pinned);
            //GCHandle.Alloc(cport, GCHandleType.Pinned);
            //GCHandle.Alloc(outport, GCHandleType.Pinned);
            //GCHandle.Alloc(infoport, GCHandleType.Pinned);

            cport.PlaySegment(segment);


Full class with DLS support for collection based on static for GC:
Code: [Select]
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using DirectMidi;
using System.Runtime.InteropServices;
using System.Diagnostics;

namespace FF8
{
    static class init_debugger_Audio
    {
        public static CDirectMusic cdm;
        public static CDLSLoader loader;
        public static CSegment segment;
        public static CAPathPerformance path;
        public static CPortPerformance cport;
        public static COutputPort outport;
        public static CCollection ccollection;
        public static CInstrument instrument;
        public static CInstrument[] instruments;


        public const int S_OK = 0x00000000;


        internal static void DEBUG()
        {

            PlayMusic();
            //FileStream fs = new FileStream(pt, FileMode.Open, FileAccess.Read);
            //BinaryReader br = new BinaryReader(fs);
            //string RIFF = Encoding.ASCII.GetString(br.ReadBytes(4));
            //if (RIFF != "RIFF") throw new Exception("NewDirectMusic::NOT RIFF");
            //uint eof = br.ReadUInt32();
            //if (fs.Length != eof + 8) throw new Exception("NewDirectMusic::RIFF length/size indicator error");
            //string dmsg = Encoding.ASCII.GetString(br.ReadBytes(4));
            //var SegmentHeader = GetSGTSection(br);
            //var guid = GetSGTSection(br);
            //var list = GetSGTSection(br);
            //var vers = GetSGTSection(br);
            //var list_unfo = GetSGTSection(br);
            //string UNFO = SGT_ReadUNAM(list_unfo).TrimEnd('\0');
            //var trackList = GetSGTSection(br);
            //List<byte[]> Tracks = ProcessTrackList(trackList.Item2);
            //byte[] sequenceTrack = Tracks[2];
            //PseudoBufferedStream pbs = new PseudoBufferedStream(sequenceTrack);
            //pbs.Seek(44, PseudoBufferedStream.SEEK_BEGIN);
            //string seqt = Encoding.ASCII.GetString(BitConverter.GetBytes(pbs.ReadUInt()));
        }

        internal static void update()

        {

        }

        unsafe private static void PlayMusic()
        {
            string pt = Memory.FF8DIR + "/../Music/dmusic/013s-battle2.sgt";
            cdm = new CDirectMusic();
            cdm.Initialize();
            loader = new CDLSLoader();
            loader.Initialize();
            loader.LoadSegment(pt, out segment);
            ccollection = new CCollection();
            loader.LoadDLS(Memory.FF8DIR + "/../Music/dmusic/FF8.dls",out ccollection );
            uint dwInstrumentIndex = 0;
            INSTRUMENTINFO iInfo;
            while (ccollection.EnumInstrument(++dwInstrumentIndex, out iInfo) == S_OK)
            {
                Debug.WriteLine(iInfo.szInstName);
            }
            instruments = new CInstrument[dwInstrumentIndex];

            path = new CAPathPerformance();
            path.Initialize(cdm, null, null, DMUS_APATH.DYNAMIC_3D, 128);
            cport = new CPortPerformance();
            cport.Initialize(cdm, null, null);
            outport = new COutputPort();
            outport.Initialize(cdm);

            uint dwPortCount = 0;
            INFOPORT infoport;
            do
                outport.GetPortInfo(++dwPortCount, out infoport);
            while ((infoport.dwFlags & DMUS_PC.SOFTWARESYNTH) == 0);

            outport.SetPortParams(0, 0, 0, SET.REVERB | SET.CHORUS, 44100);
            outport.ActivatePort(infoport);

            cport.AddPort(outport, 0, 1);

            for (int i = 0; i < dwInstrumentIndex; i++)
            {
                ccollection.GetInstrument(out instruments[i], i);
                outport.DownloadInstrument(instruments[i]);
            }
            segment.Download(cport);
            //GCHandle.Alloc(cdm, GCHandleType.Pinned);
            //GCHandle.Alloc(loader, GCHandleType.Pinned);
            //GCHandle.Alloc(segment, GCHandleType.Pinned);
            //GCHandle.Alloc(path, GCHandleType.Pinned);
            //GCHandle.Alloc(cport, GCHandleType.Pinned);
            //GCHandle.Alloc(outport, GCHandleType.Pinned);
            //GCHandle.Alloc(infoport, GCHandleType.Pinned);

            cport.PlaySegment(segment);
        }

@UPDATE:
segment.ConnectToDls takes CCollection

23
Scripting and Reverse Engineering / Re: .SGT audio
« on: 2018-06-25 12:16:00 »
I began to work with it by myself. It's hard to find any documentation about .SGT file, but I made it to split the file content into five tracks. I'm working with 0004s-run.sgt (Run from FFVIII):

Looks like every track have header like this:
TRACK HEADER:
Code: [Select]
const char[8] DMTKrekh
uint size
byte[size] UNKNOWN

UNKNOWN:
Code: [Select]
byte[24] UNKNOWN
char[4] modeIndicator1
char[4] modeIndicator2

Some tracks have modeIndicator1 filled and modeIndicator2 nulled, and some have modeIndicator1 nulled and modeIndicator2 filled.



Track#1:
Code: [Select]
TRACKHEADER 44 bytes
LIST->cord (in my example 156 bytes + 8 ('cord' and size uint))
Chords data?

Track#2:
Code: [Select]
TRACKHEADER 44 bytes
tetr (in my example 20 bytes + 8 ('tetr' and size uint))
No idea, looks quite empty

Track#3:
Code: [Select]
TRACKHEADER 44 bytes
seqt (in my example 14460 bytes + 8 ('seqt' and size uint))
---evtl (in my example 60664 bytes + 8)
---curl (in my example 83780 bytes + 8)
This needs to be the main sequence, what evtl and curl are?
FOUND IT!
https://msdn.microsoft.com/en-us/library/ms900331.aspx

Track#4:
Code: [Select]
TRACKHEADER 44 bytes
tims (in my example 20 bytes + 8 ('tims' and size uint))
No idea, looks quite empty

Track#5:
Code: [Select]
TRACKHEADER 44 bytes
RIFF CONTAINER -> DMBT -> LIST; LIST; LIST; UNFO ("Band1"); (...) Inname ("FF8 Instruments File * FF8.dls")
Probably set-up of DLS/ bands/ instruments, lot of sub-cointainers with 'LIST' indicator.


@UPDATE:
Yeah, like I found the SGT chunks documentation:
https://msdn.microsoft.com/en-us/library/ms900553.aspx
-but some pages are in JP only https://msdn.microsoft.com/ja-jp/cc354074(ja-jp)

Python, track 2/ tetr, last 8 bytes:
Code: [Select]
>struct.unpack('d', '0000000000405f40'.decode('hex'))[0]
125.0


dmusicf.h found at:
https://github.com/tycho/arc/blob/master/contrib/DirectX/include/dmusicf.h

Sequence:
Code: [Select]
typedef struct _DMUS_IO_SEQ_ITEM
{
    MUSIC_TIME    mtTime;
    MUSIC_TIME    mtDuration;
    DWORD         dwPChannel;
    short         nOffset;
    BYTE          bStatus;
    BYTE          bByte1;
    BYTE          bByte2;
} DMUS_IO_SEQ_ITEM;


typedef struct _DMUS_IO_CURVE_ITEM
{
    MUSIC_TIME  mtStart;
    MUSIC_TIME  mtDuration;
    MUSIC_TIME  mtResetDuration;
    DWORD       dwPChannel;
    short       nOffset;
    short       nStartValue;
    short       nEndValue;
    short       nResetValue;
    BYTE        bType;
    BYTE        bCurveShape;
    BYTE        bCCData;
    BYTE        bFlags;
} DMUS_IO_CURVE_ITEM;

24
Hoarding again through the FF executables I found the .dotemu references. Quickly found out it's a game porting studio. Here's the interview:
https://squarebd1.wordpress.com/2016/01/27/my-interview-with-dotemu-the-studio-behind-many-recent-final-fantasy-ports/

From my personal experience working in commercial gamedev industry, porting game is usually hacking it on your own to make it working with current gen (in case of retro games there's almost never a source code, just an ISO). However, dotemu actually said the dev department of SE did in fact provide support for their game, which happens quite rare. We can't talk about source code for sure, but I think they actually remembered how things go and for example how to use AF3DN.P for memory injection and passed that info to dotemu.

25
Scripting and Reverse Engineering / .SGT audio
« on: 2018-06-24 11:59:50 »
I'm currently on hunt to implement .SGT playing. I got many needed information like how is RIFF container with DMSG built, like here: http://www.vgmpf.com/Wiki/index.php?title=SGT
It's part of DirectMusic that was a part of Dx8, yet I've seen the FMOD works with .SGT and .DLS media. I grabbed FMOD, made the wrappers working and tested with .MP3 and .MID files work flawless yet on .SGT it throws ERR_FORMAT like it doesn't know how to play .SGT (yet it loads .DLS bank properly). I browsed the web and found the FMUSIC of FMOD is capable of playing .SGT, but it's like 14 years ago and no such thing as FMUSIC exists anymore. Therefore- is any of you aware of any library that supports playing .SGT? Or converting to .MID or almost anything else I can use on good license and is capable of storing the data in memory only? I'm trying to implement an audio playing working on real files instead of re-converting them (or at least not leaving any trash behind). I'm working with Dx11, so I can't just grab the old DirectMusic from dx8

Working C# example in my last post!

Basically C# wrapper of C++ wrapper of Dx8 DirectMusic

Pages: [1] 2 3 ... 21