Comments (10)
It's complicated. Here is the Ghidra Project I've been using. Open INTRO.EXE
as it is only meant to play game videos, and surprisingly, can play XMF music along provided it is named URES.XMF
.
I've noticed these modules are very quiet.
Not that quiet, volume is probably between 0x00 and 0x40. I added the global volume straight (not scaled).
MAIN1.ZIP
from libmodplug.
Effects testing module with all of the working effects, plus the original MOD and a recording of DOSBox's audio with the Gravis UltraSound driver: xmftest.zip
All of my other effects and sample findings, and the custom MOD to XMF converter I wrote for testing: https://gist.github.com/AliceLR/deeb651c7629c8ee4b8a079f62304827
Given that the official XMFs only use effects Axy
, Cxx
, EAx
, EBx
, Fxx
, 10xy
, and that 10xy
is directly compatible with Ultra Tracker Bxy
(or can be dropped if you don't want panning), converting to ULT will probably work.
from libmodplug.
A couple of things:
- To the best of my knowledge, the ULT format does not support the Set Global Volume effect.
- libmodplug fundamentally can not properly support ULT or ULT-like formats because it does not have two full effects channels. libxmp and libopenmpt can, but that doesn't help with VLC.
- ULT also has some really weird behaviors, especially regarding finetune, and I don't recommend using it as an intermediate format for anything.
Which game format are you trying to convert?
from libmodplug.
Imperium Galactica 1 (1996) XMF.
The conversion to ULT does work 99%. I know it doesn't support set global volume; I'm trying to emulate it.
So the question still remains: how do I do it? How do other formats, which support 0x10 calculate the actual note volume?
Edit:
Looking through libxmp, I found these:
https://github.com/libxmp/libxmp/blob/master/src/player.c#L309-L310
https://github.com/libxmp/libxmp/blob/master/src/player.c#L989-L991
So either
volume_actual = volume_global * volume_current * other_factors >> 24
volume_actual = volume_global * volume_current >> 12
from libmodplug.
After doing a bit of reverse engineering, it seems that every instance of effect 10h
is only used with a parameter in the range from 0-f. Given this and what looks like a channel default panning table that starts at offset 1103h
: this is probably not global volume, but rather Gravis UltraSound-style 4-bit panning.
This is pure speculation: the author's previous game Reunion uses MODs, so if this format was based on ULT, Tamas Kreiner may not have liked that Ultra Tracker uses the Bxx
effect for panning, so he moved it to 10xx
instead. That said, it doesn't seem like any of these modules use Bxx
at all.
Since Ultra Tracker uses 4-bit panning, you should just be able to directly convert effect 10xx
to Bxx
if it really is panning.
from libmodplug.
Since Ultra Tracker uses 4-bit panning, you should just be able to directly convert effect
10xx
toBxx
if it really is panning.
I tried that already. It resulted in an output where each track had its distinct pan position throughout the music, which was completely different how the same music sounds ingame - centered mono.
Reverse engineering the music code, it looked like when 10
is executed, the issues Gravis volume slide commands relative to the current and global volume.
Ghidra Decompiled Code
CX = xmf_sample_count + byte_5ac7
BP = channel index
For each channels
LAB_1010_31d7 XREF[1]: 1010:3251 (j)
1010:31d7 8b f5 MOV SI,BP
1010:31d9 d1 ee SHR SI,0x1
1010:31db 65 80 bc CMP byte ptr GS:[SI + smp_global_volume ],0xff
73 4f ff
1010:31e1 74 14 JZ LAB_1010_31f7
1010:31e3 65 8a 84 MOV AL,byte ptr GS:[SI + smp_volume_curr ]
93 4f
1010:31e8 65 2a 84 SUB AL,byte ptr GS:[SI + smp_global_volume ]
73 4f
1010:31ed 0a c0 OR AL,AL
1010:31ef 79 02 JNS LAB_1010_31f3
1010:31f1 f6 d8 NEG AL
LAB_1010_31f3 XREF[1]: 1010:31ef (j)
1010:31f3 3c 05 CMP AL,0x5
1010:31f5 72 56 JC LAB_1010_324d
LAB_1010_31f7 XREF[1]: 1010:31e1 (j)
1010:31f7 c1 e6 02 SHL SI,0x2
1010:31fa 66 65 83 CMP dword ptr GS:[SI + Smp_Play_Index ],-0x1
bc 33 4e ff
1010:3201 74 4a JZ LAB_1010_324d
1010:3203 65 8b 16 MOV DX,word ptr GS:[SB_Port ] = 240h
ab 5a
1010:3208 81 c2 02 01 ADD DX,0x102
1010:320c 8b c5 MOV AX,BP
1010:320e d1 e8 SHR AX,0x1
GUS Select Voice (BP >> 1)
Base + 0x102
1010:3210 ee OUT DX,AL
1010:3211 42 INC DX
1010:3212 b0 0d MOV AL,0xd
GUS Set Volume Control
Base + 0x103
1010:3214 ee OUT DX,AL
1010:3215 83 c2 02 ADD DX,0x2
1010:3218 b0 03 MOV AL,0x3
Base + 0x105 <- 0x3 (Volume Stopped | Stop Volume)
1010:321a ee OUT DX,AL
1010:321b 83 ea 02 SUB DX,0x2
1010:321e b0 07 MOV AL,0x7
Base + 0x103 <- Set Volume Start
1010:3220 ee OUT DX,AL
1010:3221 42 INC DX
1010:3222 65 a1 98 6b MOV AX,GS:[Volume_Start_W ]
Base + 0x104 <- Voice_Volume_Start Word
1010:3226 ef OUT DX,AX
1010:3227 4a DEC DX
1010:3228 b0 08 MOV AL,0x8
Gus Set Volume End
Base + 0x103 <- 0x08
1010:322a ee OUT DX,AL
1010:322b 42 INC DX
1010:322c 65 8b 86 MOV AX,word ptr GS:[BP + Voice_Volume_End_W ]
47 54
1010:3231 65 3b 06 CMP AX,word ptr GS:[Volume_Table ] = A00h
96 6b
1010:3236 74 15 JZ LAB_1010_324d
1010:3238 65 8b 1e MOV BX,word ptr GS:[Volume_Start_W ]
98 6b
1010:323d 65 89 9e MOV word ptr GS:[BP + Voice_Volume_End_W ],BX
47 54
Base + 0x104 <- Voice_Volume_End
1010:3242 ef OUT DX,AX
1010:3243 4a DEC DX
1010:3244 b0 0d MOV AL,0xd
Base + 0x103 <- Set Volume Control
1010:3246 ee OUT DX,AL
1010:3247 83 c2 02 ADD DX,0x2
1010:324a b0 40 MOV AL,0x40
base + 0x105 <- 0x40 (Volume_Direct)
1010:324c ee OUT DX,AL
LAB_1010_324d XREF[3]: 1010:31f5 (j) , 1010:3201 (j) , 1010:3236 (j)
1010:324d 83 c5 02 ADD BP,0x2
1010:3250 49 DEC CX
1010:3251 75 84 JNZ LAB_1010_31d7
1010:3253 61 POPA
1010:3254 0f a9 POP GS
1010:3256 cf IRET
So if it is for global volume, I'd have to try another mod format that accepts 10
natively. However, FastTracker's XM format looks too convoluted. What would be the closest format to ULT?
from libmodplug.
I think the following would work for global volume, at least to experiment with. The following would have to be applied to every event with a note or with a volume or 10xx
:
if Cxx
is used: volume = [ cxx_param * global_volume ] / global_volume_max
else: volume = [ instrument_default_volume * global_volume ] / global_volume_max
Cxx
and instrument default volume both look like they're 0-255, so the same formula ought to work...
Reverse engineering the music code, it looked like when
10
is executed, the issues Gravis volume slide commands relative to the current and global volume.
OK, I'll try to make sense of this in a little bit.
from libmodplug.
This disassembly looks like GUS volume ramping. There are a few things that aren't clear currently:
- Where is GUS voice register 0x6 (volume increment) being written? Is this what command
10
changes? - How is
Volume_Start_W
and the initial value ofVoice_Volume_End_W[channel]
set? - Where does
smp_global_volume[channel]
come from?
This command plausibly might be meant to trigger the volume ramps, or to at least control the rate at which they're performed for the current channel.
I'm working on basic support for this format for libxmp, and I've noticed these modules are very quiet. Is that normal?
from libmodplug.
Addendum to 0x10 and quietness: I'm 99% sure this is Set Global Volume
command of FastTracker ][.
from libmodplug.
More effects info coming when I finish black box testing, but I figured out 10xx
. It is Gravis UltraSound panning, and is not implemented for the Sound Blaster driver:
More typical MOD extended panning effects (8xx
, E8x
) do not work.
from libmodplug.
Related Issues (20)
- Crash when reading a specific file HOT 4
- Public Domain declaration has problems HOT 2
- Seeking to invalid position doesn't report failure
- LSB/MSB byte order on ppc/linux (powerpc, 32bit) HOT 2
- Documentation? HOT 1
- Add support for MAD* files (MADH/MADfg/MADI/MADK) HOT 2
- AMF Player (ReadAMF?) can't play correctly .amf files from Cannon Fodder 2 soundtrack
- Midi music get wrong duration && wrong tone HOT 1
- Please publish a git tag for the 0.8.9.0 release HOT 1
- Having trouble looping sounds HOT 1
- Segmentation fault in mmreadUBYTE(MMFILE*) HOT 4
- Missing git version tags HOT 1
- 0.8.9.0: compile time warnings HOT 9
- release early, release often
- [Feature Request] Mugician and Future Composer support HOT 1
- unable to play some s3m file HOT 1
- S3M requires 6 bytes after last pattern before end of file HOT 1
- [Feature Request] PlaySID v2.2+ (AMIGA) sidtune support
- Enhancing libmodplug's playback support for MIDI files and other "instrument-free" music formats
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from libmodplug.