MIDI support

Open-source port of PoP that runs natively on Windows, Linux, etc.
Falcury
Calif
Calif
Posts: 565
Joined: June 25th, 2009, 10:01 pm

MIDI support

Post by Falcury »

I would like to look into adding support for (AdLib) MIDI sounds in a future release.

As was requested and discussed some time ago on GitHub:
https://github.com/NagyD/SDLPoP/issues/25

On GitHub, myself600 recommended integrating Chocolate Doom's OPL code

I looked at that code a bit, and it seems like a good base to start from. The Doom code has a lot of boilerplate for supporting various drivers, though, which we don't really need for SDLPoP (the SDL 'driver' is enough). They also use SDL_Mixer, which isn't needed for SDLPoP.
I expect that we could end up using opl3.c/opl3.h as-is, and modify or rewrite the rest to suit our purposes.
I already wrote some code for parsing the MIDI files into tracks and events. But that will still need to be wired up to the OPL3 emulator somehow.

And regarding the instrument definitions for PoP, I see that David already figured out most of it (looking at the V1.0 disassembly).
If I understand the disassembly correctly, there is only one hardcoded instrument, right? (namely, the 16-byte instrument_type structure at seg035:017C)
Do you think it will it be enough to write the appropriate values to each OPL register, and then forget about it for the rest of the song?

I haven't understood yet how MIDI messages are handled exactly.
Hopefully it will be possible to adapt the work done in Chocolate Doom, in such a way that it outputs the correct sounds from Prince of Persia.

Some useful references I've found:
http://www.vgmpf.com/Wiki/index.php/Pri ... rsia_(DOS) (information on the various PoP sounds)
http://www.shipbrook.net/jeff/sb.html (programming the OPL2 chip)
http://www.fit.vutbr.cz/~arnost/opl/opl3.html (programming the OPL2/OPL3 chip)
https://www.csie.ntu.edu.tw/~r92092/ref/midi/ (MIDI file format)
https://www.midi.org/specifications (more information on the MIDI format)
David
The Prince of Persia
The Prince of Persia
Posts: 2846
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: MIDI support

Post by David »

Falcury wrote: February 18th, 2018, 12:13 pm And regarding the instrument definitions for PoP, I see that David already figured out most of it (looking at the V1.0 disassembly).
If I understand the disassembly correctly, there is only one hardcoded instrument, right? (namely, the 16-byte instrument_type structure at seg035:017C)
While that is there, I don't think it's used.
Instead, the game loads instruments' data from PRINCE.DAT, resource ID 1.
Falcury
Calif
Calif
Posts: 565
Joined: June 25th, 2009, 10:01 pm

Re: MIDI support

Post by Falcury »

David wrote: February 18th, 2018, 5:16 pm While that is there, I don't think it's used.
Instead, the game loads instruments' data from PRINCE.DAT, resource ID 1.
Thank you, that is good to know!

I just now got the instruments from resource ID 1 to work. They sound familiar :)
I have started writing a small stand-alone program that will play back the MIDI files.

Here's some debug output for one of the MIDI files:

Code: Select all

Track 0: Event 0 (dt=0): type = ff; meta event (length=12): sequence/track name: Prolog1a.mff
Track 0: Event 1 (dt=0): type = ff; meta event (length=5): SMTPE offset: 60 00 00 00 00
Track 0: Event 2 (dt=0): type = ff; meta event (length=4): time signature: 04 02 18 08
Track 0: Event 3 (dt=0): type = ff; meta event (length=3): set tempo: 08 52 ae
Track 0: Event 4 (dt=0): type = c0; program change: ch 1, par 0
Track 0: Event 5 (dt=0): type = c0; program change: ch 3, par 2
Track 0: Event 6 (dt=0): type = c0; program change: ch 4, par 6
Track 0: Event 7 (dt=0): type = c0; program change: ch 5, par 2
Track 0: Event 8 (dt=0): type = 90; noteon: ch 3, par 1a|40
Track 0: Event 9 (dt=0): type = f0; sysex event (length=7): 00 00 34 01 00 0c f7
Track 0: Event 10 (dt=0): type = c0; program change: ch 0, par 0
Track 0: Event 11 (dt=0): type = c0; program change: ch 2, par 2
Track 0: Event 12 (dt=0): type = 90; noteon: ch 2, par 26|40
Track 0: Event 13 (dt=0): type = c0; program change: ch 6, par 3
Track 0: Event 14 (dt=480): type = 80; noteoff: ch 3, par 1a|40
Track 0: Event 15 (dt=0): type = 80; noteoff: ch 2, par 26|40
Track 0: Event 16 (dt=0): type = 90; noteon: ch 3, par 21|30
Track 0: Event 17 (dt=0): type = 90; noteon: ch 2, par 2d|28
Track 0: Event 18 (dt=160): type = 80; noteoff: ch 3, par 21|40
Track 0: Event 19 (dt=0): type = 80; noteoff: ch 2, par 2d|40
Track 0: Event 20 (dt=0): type = 90; noteon: ch 3, par 21|30
Track 0: Event 21 (dt=0): type = 90; noteon: ch 2, par 2d|28
Track 0: Event 22 (dt=160): type = 80; noteoff: ch 3, par 21|40
Track 0: Event 23 (dt=0): type = 80; noteoff: ch 2, par 2d|40
Track 0: Event 24 (dt=0): type = 90; noteon: ch 3, par 21|30
Track 0: Event 25 (dt=0): type = 90; noteon: ch 2, par 2d|28
Track 0: Event 26 (dt=120): type = 80; noteoff: ch 3, par 21|40
Track 0: Event 27 (dt=0): type = 80; noteoff: ch 2, par 2d|40
Track 0: Event 28 (dt=0): type = 90; noteon: ch 3, par 22|30
Track 0: Event 29 (dt=0): type = 90; noteon: ch 2, par 2e|28
Track 0: Event 30 (dt=40): type = 80; noteoff: ch 3, par 22|40
Track 0: Event 31 (dt=0): type = 80; noteoff: ch 2, par 2e|40
Track 0: Event 32 (dt=0): type = 90; noteon: ch 3, par 21|30
Track 0: Event 33 (dt=0): type = 90; noteon: ch 2, par 2d|28
Track 0: Event 34 (dt=480): type = 80; noteoff: ch 3, par 21|40
Track 0: Event 35 (dt=0): type = 80; noteoff: ch 2, par 2d|40
Track 0: Event 36 (dt=0): type = 90; noteon: ch 3, par 21|30
Track 0: Event 37 (dt=0): type = 90; noteon: ch 2, par 2d|28
Track 0: Event 38 (dt=440): type = 90; noteon: ch 1, par 3a|40
Track 0: Event 39 (dt=0): type = 90; noteon: ch 0, par 3f|40
Track 0: Event 40 (dt=0): type = 90; noteon: ch 6, par 3f|40
Track 0: Event 41 (dt=40): type = 80; noteoff: ch 3, par 21|40
Track 0: Event 42 (dt=0): type = 80; noteoff: ch 2, par 2d|40
Track 0: Event 43 (dt=0): type = 80; noteoff: ch 1, par 3a|40
Track 0: Event 44 (dt=0): type = 80; noteoff: ch 0, par 3f|40
Track 0: Event 45 (dt=0): type = 80; noteoff: ch 6, par 3f|40
Track 0: Event 46 (dt=0): type = 90; noteon: ch 3, par 1a|40
Track 0: Event 47 (dt=0): type = 90; noteon: ch 2, par 26|40
Track 0: Event 48 (dt=0): type = 90; noteon: ch 1, par 39|30
Track 0: Event 49 (dt=0): type = 90; noteon: ch 0, par 3e|40
Track 0: Event 50 (dt=0): type = 90; noteon: ch 6, par 3e|30
Track 0: Event 51 (dt=480): type = 80; noteoff: ch 3, par 1a|40
Track 0: Event 52 (dt=0): type = 80; noteoff: ch 2, par 26|40
Track 0: Event 53 (dt=0): type = 90; noteon: ch 3, par 21|30
Track 0: Event 54 (dt=0): type = 90; noteon: ch 2, par 2d|28
Track 0: Event 55 (dt=160): type = 80; noteoff: ch 3, par 21|40
Track 0: Event 56 (dt=0): type = 80; noteoff: ch 2, par 2d|40
Track 0: Event 57 (dt=0): type = 90; noteon: ch 3, par 21|30
Track 0: Event 58 (dt=0): type = 90; noteon: ch 2, par 2d|28
Track 0: Event 59 (dt=160): type = 80; noteoff: ch 3, par 21|40
Track 0: Event 60 (dt=0): type = 80; noteoff: ch 2, par 2d|40
Track 0: Event 61 (dt=0): type = 90; noteon: ch 3, par 21|30
Track 0: Event 62 (dt=0): type = 90; noteon: ch 2, par 2d|28
Track 0: Event 63 (dt=160): type = 80; noteoff: ch 3, par 21|40
Track 0: Event 64 (dt=0): type = 80; noteoff: ch 2, par 2d|40
Track 0: Event 65 (dt=0): type = 90; noteon: ch 3, par 26|30
Track 0: Event 66 (dt=0): type = 90; noteon: ch 2, par 32|28
Track 0: Event 67 (dt=480): type = 80; noteoff: ch 1, par 39|40
Track 0: Event 68 (dt=0): type = 80; noteoff: ch 0, par 3e|40
Track 0: Event 69 (dt=0): type = 80; noteoff: ch 6, par 3e|40
Track 0: Event 70 (dt=0): type = 80; noteoff: ch 3, par 26|40
Track 0: Event 71 (dt=0): type = 80; noteoff: ch 2, par 32|40
Track 0: Event 72 (dt=0): type = 90; noteon: ch 0, par 3f|40
Track 0: Event 73 (dt=0): type = 90; noteon: ch 6, par 3f|30
Track 0: Event 74 (dt=0): type = 90; noteon: ch 3, par 21|30
Track 0: Event 75 (dt=0): type = 90; noteon: ch 2, par 2d|28
Track 0: Event 76 (dt=160): type = 80; noteoff: ch 0, par 3f|40
Track 0: Event 77 (dt=0): type = 80; noteoff: ch 6, par 3f|40
Track 0: Event 78 (dt=0): type = 90; noteon: ch 0, par 42|40
Track 0: Event 79 (dt=0): type = 90; noteon: ch 6, par 42|30
Track 0: Event 80 (dt=160): type = 80; noteoff: ch 0, par 42|40
Track 0: Event 81 (dt=0): type = 80; noteoff: ch 6, par 42|40
Track 0: Event 82 (dt=0): type = 90; noteon: ch 0, par 3f|40
Track 0: Event 83 (dt=0): type = 90; noteon: ch 6, par 3f|40
Track 0: Event 84 (dt=160): type = 80; noteoff: ch 3, par 21|40
Track 0: Event 85 (dt=0): type = 80; noteoff: ch 2, par 2d|40
Track 0: Event 86 (dt=0): type = 80; noteoff: ch 0, par 3f|40
Track 0: Event 87 (dt=0): type = 80; noteoff: ch 6, par 3f|40
Track 0: Event 88 (dt=0): type = 90; noteon: ch 1, par 39|30
Track 0: Event 89 (dt=0): type = 90; noteon: ch 3, par 1a|40
Track 0: Event 90 (dt=0): type = 90; noteon: ch 2, par 26|40
Track 0: Event 91 (dt=0): type = 90; noteon: ch 0, par 3e|40
Track 0: Event 92 (dt=0): type = 90; noteon: ch 6, par 3e|30
Track 0: Event 93 (dt=480): type = 80; noteoff: ch 3, par 1a|40
Track 0: Event 94 (dt=0): type = 80; noteoff: ch 2, par 26|40
Track 0: Event 95 (dt=0): type = 90; noteon: ch 3, par 21|30
Track 0: Event 96 (dt=0): type = 90; noteon: ch 2, par 2d|28
Track 0: Event 97 (dt=160): type = 80; noteoff: ch 3, par 21|40
Track 0: Event 98 (dt=0): type = 80; noteoff: ch 2, par 2d|40
Track 0: Event 99 (dt=0): type = 90; noteon: ch 3, par 21|30
Track 0: Event 100 (dt=0): type = 90; noteon: ch 2, par 2d|28
Track 0: Event 101 (dt=160): type = 80; noteoff: ch 3, par 21|40
Track 0: Event 102 (dt=0): type = 80; noteoff: ch 2, par 2d|40
Track 0: Event 103 (dt=0): type = 90; noteon: ch 3, par 21|30
Track 0: Event 104 (dt=0): type = 90; noteon: ch 2, par 2d|28
Track 0: Event 105 (dt=120): type = 80; noteoff: ch 3, par 21|40
Track 0: Event 106 (dt=0): type = 80; noteoff: ch 2, par 2d|40
Track 0: Event 107 (dt=0): type = 90; noteon: ch 3, par 22|30
Track 0: Event 108 (dt=0): type = 90; noteon: ch 2, par 2e|28
Track 0: Event 109 (dt=40): type = 80; noteoff: ch 3, par 22|40
Track 0: Event 110 (dt=0): type = 80; noteoff: ch 2, par 2e|40
Track 0: Event 111 (dt=0): type = 90; noteon: ch 3, par 21|30
Track 0: Event 112 (dt=0): type = 90; noteon: ch 2, par 2d|28
Track 0: Event 113 (dt=480): type = 80; noteoff: ch 1, par 39|40
Track 0: Event 114 (dt=0): type = 80; noteoff: ch 0, par 3e|40
Track 0: Event 115 (dt=0): type = 80; noteoff: ch 6, par 3e|40
Track 0: Event 116 (dt=0): type = 80; noteoff: ch 3, par 21|40
Track 0: Event 117 (dt=0): type = 80; noteoff: ch 2, par 2d|40
Track 0: Event 118 (dt=0): type = 90; noteon: ch 3, par 21|30
Track 0: Event 119 (dt=0): type = 90; noteon: ch 2, par 2d|28
Track 0: Event 120 (dt=440): type = 90; noteon: ch 1, par 3f|40
Track 0: Event 121 (dt=0): type = 90; noteon: ch 0, par 44|40
Track 0: Event 122 (dt=0): type = 90; noteon: ch 6, par 44|40
Track 0: Event 123 (dt=40): type = 80; noteoff: ch 3, par 21|40
Track 0: Event 124 (dt=0): type = 80; noteoff: ch 2, par 2d|40
Track 0: Event 125 (dt=0): type = 80; noteoff: ch 1, par 3f|40
Track 0: Event 126 (dt=0): type = 80; noteoff: ch 0, par 44|40
Track 0: Event 127 (dt=0): type = 80; noteoff: ch 6, par 44|40
Track 0: Event 128 (dt=0): type = 90; noteon: ch 3, par 1f|40
Track 0: Event 129 (dt=0): type = 90; noteon: ch 2, par 2b|40
Track 0: Event 130 (dt=0): type = 90; noteon: ch 1, par 3e|30
Track 0: Event 131 (dt=0): type = 90; noteon: ch 0, par 43|40
Track 0: Event 132 (dt=0): type = 90; noteon: ch 6, par 43|30
Track 0: Event 133 (dt=480): type = 80; noteoff: ch 3, par 1f|40
Track 0: Event 134 (dt=0): type = 80; noteoff: ch 2, par 2b|40
Track 0: Event 135 (dt=0): type = 90; noteon: ch 3, par 26|30
Track 0: Event 136 (dt=0): type = 90; noteon: ch 2, par 32|28
Track 0: Event 137 (dt=160): type = 80; noteoff: ch 3, par 26|40
Track 0: Event 138 (dt=0): type = 80; noteoff: ch 2, par 32|40
Track 0: Event 139 (dt=0): type = 90; noteon: ch 3, par 26|30
Track 0: Event 140 (dt=0): type = 90; noteon: ch 2, par 32|28
Track 0: Event 141 (dt=160): type = 80; noteoff: ch 3, par 26|40
Track 0: Event 142 (dt=0): type = 80; noteoff: ch 2, par 32|40
Track 0: Event 143 (dt=0): type = 90; noteon: ch 3, par 26|30
Track 0: Event 144 (dt=0): type = 90; noteon: ch 2, par 32|28
Track 0: Event 145 (dt=160): type = 80; noteoff: ch 3, par 26|40
Track 0: Event 146 (dt=0): type = 80; noteoff: ch 2, par 32|40
Track 0: Event 147 (dt=0): type = 90; noteon: ch 3, par 2b|30
Track 0: Event 148 (dt=0): type = 90; noteon: ch 2, par 37|28
Track 0: Event 149 (dt=480): type = 80; noteoff: ch 1, par 3e|40
Track 0: Event 150 (dt=0): type = 80; noteoff: ch 0, par 43|40
Track 0: Event 151 (dt=0): type = 80; noteoff: ch 6, par 43|40
Track 0: Event 152 (dt=0): type = 80; noteoff: ch 3, par 2b|40
Track 0: Event 153 (dt=0): type = 80; noteoff: ch 2, par 37|40
Track 0: Event 154 (dt=0): type = 90; noteon: ch 0, par 44|40
Track 0: Event 155 (dt=0): type = 90; noteon: ch 6, par 44|30
Track 0: Event 156 (dt=0): type = 90; noteon: ch 3, par 26|30
Track 0: Event 157 (dt=0): type = 90; noteon: ch 2, par 32|28
Track 0: Event 158 (dt=160): type = 80; noteoff: ch 0, par 44|40
Track 0: Event 159 (dt=0): type = 80; noteoff: ch 6, par 44|40
Track 0: Event 160 (dt=0): type = 90; noteon: ch 0, par 47|40
Track 0: Event 161 (dt=0): type = 90; noteon: ch 6, par 47|30
Track 0: Event 162 (dt=160): type = 80; noteoff: ch 0, par 47|40
Track 0: Event 163 (dt=0): type = 80; noteoff: ch 6, par 47|40
Track 0: Event 164 (dt=0): type = 90; noteon: ch 0, par 44|40
Track 0: Event 165 (dt=0): type = 90; noteon: ch 6, par 44|30
Track 0: Event 166 (dt=160): type = ff; meta event (length=3): set tempo: 09 27 c0
Track 0: Event 167 (dt=0): type = 80; noteoff: ch 3, par 26|40
Track 0: Event 168 (dt=0): type = 80; noteoff: ch 2, par 32|40
Track 0: Event 169 (dt=0): type = 80; noteoff: ch 0, par 44|40
Track 0: Event 170 (dt=0): type = 80; noteoff: ch 6, par 44|40
Track 0: Event 171 (dt=0): type = 90; noteon: ch 1, par 3e|30
Track 0: Event 172 (dt=0): type = 90; noteon: ch 0, par 43|40
Track 0: Event 173 (dt=0): type = 90; noteon: ch 6, par 43|30
Track 0: Event 174 (dt=0): type = 90; noteon: ch 3, par 1f|40
Track 0: Event 175 (dt=0): type = 90; noteon: ch 2, par 2b|40
Track 0: Event 176 (dt=480): type = ff; meta event (length=3): set tempo: 0a 2c 2a
Track 0: Event 177 (dt=0): type = 80; noteoff: ch 3, par 1f|40
Track 0: Event 178 (dt=0): type = 80; noteoff: ch 2, par 2b|40
Track 0: Event 179 (dt=0): type = 90; noteon: ch 3, par 26|36
Track 0: Event 180 (dt=0): type = 90; noteon: ch 2, par 32|30
Track 0: Event 181 (dt=160): type = 80; noteoff: ch 3, par 26|40
Track 0: Event 182 (dt=0): type = 80; noteoff: ch 2, par 32|40
Track 0: Event 183 (dt=0): type = 90; noteon: ch 3, par 26|32
Track 0: Event 184 (dt=0): type = 90; noteon: ch 2, par 32|2d
Track 0: Event 185 (dt=160): type = 80; noteoff: ch 3, par 26|40
Track 0: Event 186 (dt=0): type = 80; noteoff: ch 2, par 32|40
Track 0: Event 187 (dt=0): type = 90; noteon: ch 3, par 26|2f
Track 0: Event 188 (dt=0): type = 90; noteon: ch 2, par 32|2b
Track 0: Event 189 (dt=120): type = 80; noteoff: ch 3, par 26|40
Track 0: Event 190 (dt=0): type = 80; noteoff: ch 2, par 32|40
Track 0: Event 191 (dt=0): type = 90; noteon: ch 3, par 27|2c
Track 0: Event 192 (dt=0): type = 90; noteon: ch 2, par 33|29
Track 0: Event 193 (dt=40): type = ff; meta event (length=3): set tempo: 0b 71 b0
Track 0: Event 194 (dt=0): type = 80; noteoff: ch 3, par 27|40
Track 0: Event 195 (dt=0): type = 80; noteoff: ch 2, par 33|40
Track 0: Event 196 (dt=0): type = 90; noteon: ch 3, par 26|2c
Track 0: Event 197 (dt=0): type = 90; noteon: ch 2, par 32|29
Track 0: Event 198 (dt=480): type = ff; meta event (length=3): set tempo: 0c 35 00
Track 0: Event 199 (dt=0): type = 80; noteoff: ch 1, par 3e|40
Track 0: Event 200 (dt=0): type = 80; noteoff: ch 0, par 43|40
Track 0: Event 201 (dt=0): type = 80; noteoff: ch 6, par 43|40
Track 0: Event 202 (dt=0): type = 80; noteoff: ch 3, par 26|40
Track 0: Event 203 (dt=0): type = 80; noteoff: ch 2, par 32|40
Track 0: Event 204 (dt=0): type = 90; noteon: ch 2, par 32|22
Track 0: Event 205 (dt=0): type = 90; noteon: ch 3, par 26|24
Track 0: Event 206 (dt=240): type = c0; program change: ch 1, par 4
Track 0: Event 207 (dt=240): type = ff; meta event (length=3): set tempo: 0b 71 b0
Track 0: Event 208 (dt=0): type = 80; noteoff: ch 2, par 32|40
Track 0: Event 209 (dt=0): type = 80; noteoff: ch 3, par 26|40
Track 0: Event 210 (dt=0): type = 90; noteon: ch 5, par 32|40
Track 0: Event 211 (dt=0): type = 90; noteon: ch 4, par 3e|40
Track 0: Event 212 (dt=0): type = 90; noteon: ch 0, par 3b|50
Track 0: Event 213 (dt=0): type = 90; noteon: ch 6, par 3b|20
Track 0: Event 214 (dt=0): type = 90; noteon: ch 2, par 2b|50
Track 0: Event 215 (dt=0): type = 90; noteon: ch 3, par 1f|40
Track 0: Event 216 (dt=0): type = 90; noteon: ch 1, par 2b|70
Track 0: Event 217 (dt=240): type = 80; noteoff: ch 1, par 2b|6e
Track 0: Event 218 (dt=240): type = 90; noteon: ch 1, par 2b|70
Track 0: Event 219 (dt=240): type = 80; noteoff: ch 1, par 2b|75
Track 0: Event 220 (dt=480): type = 90; noteon: ch 1, par 2f|70
Track 0: Event 221 (dt=60): type = 80; noteoff: ch 1, par 2f|4d
Track 0: Event 222 (dt=20): type = 90; noteon: ch 1, par 2f|70
Track 0: Event 223 (dt=60): type = 80; noteoff: ch 1, par 2f|4d
Track 0: Event 224 (dt=20): type = 90; noteon: ch 1, par 2f|70
Track 0: Event 225 (dt=60): type = 80; noteoff: ch 1, par 2f|46
Track 0: Event 226 (dt=20): type = 80; noteoff: ch 5, par 32|40
Track 0: Event 227 (dt=0): type = 80; noteoff: ch 4, par 3e|40
Track 0: Event 228 (dt=0): type = 80; noteoff: ch 0, par 3b|40
Track 0: Event 229 (dt=0): type = 80; noteoff: ch 6, par 3b|40
Track 0: Event 230 (dt=0): type = 80; noteoff: ch 2, par 2b|40
Track 0: Event 231 (dt=0): type = 80; noteoff: ch 3, par 1f|40
Track 0: Event 232 (dt=0): type = 90; noteon: ch 5, par 33|50
Track 0: Event 233 (dt=0): type = 90; noteon: ch 4, par 3f|50
Track 0: Event 234 (dt=0): type = 90; noteon: ch 0, par 47|50
Track 0: Event 235 (dt=0): type = 90; noteon: ch 6, par 47|20
Track 0: Event 236 (dt=0): type = 90; noteon: ch 2, par 2a|50
Track 0: Event 237 (dt=0): type = 90; noteon: ch 3, par 1e|40
Track 0: Event 238 (dt=0): type = 90; noteon: ch 1, par 2f|70
Track 0: Event 239 (dt=120): type = 80; noteoff: ch 1, par 2f|68
Track 0: Event 240 (dt=120): type = 90; noteon: ch 1, par 2f|70
Track 0: Event 241 (dt=120): type = 80; noteoff: ch 1, par 2f|54
Track 0: Event 242 (dt=80): type = c0; program change: ch 6, par 9
Track 0: Event 243 (dt=0): type = 80; noteoff: ch 6, par 47|40
Track 0: Event 244 (dt=20): type = c0; program change: ch 0, par 5
Track 0: Event 245 (dt=0): type = 80; noteoff: ch 0, par 47|40
Track 0: Event 246 (dt=20): type = 80; noteoff: ch 5, par 33|40
Track 0: Event 247 (dt=0): type = 80; noteoff: ch 4, par 3f|40
Track 0: Event 248 (dt=0): type = 80; noteoff: ch 2, par 2a|40
Track 0: Event 249 (dt=0): type = 80; noteoff: ch 3, par 1e|40
Track 0: Event 250 (dt=0): type = 90; noteon: ch 5, par 34|50
Track 0: Event 251 (dt=0): type = 90; noteon: ch 4, par 3b|60
Track 0: Event 252 (dt=0): type = 90; noteon: ch 2, par 28|50
Track 0: Event 253 (dt=0): type = 90; noteon: ch 3, par 1c|40
Track 0: Event 254 (dt=0): type = 90; noteon: ch 1, par 28|70
Track 0: Event 255 (dt=0): type = 90; noteon: ch 6, par 40|30
Track 0: Event 256 (dt=0): type = 90; noteon: ch 0, par 40|50
Track 0: Event 257 (dt=240): type = 80; noteoff: ch 1, par 28|4c
Track 0: Event 258 (dt=200): type = 80; noteoff: ch 5, par 34|40
Track 0: Event 259 (dt=0): type = 80; noteoff: ch 2, par 28|40
Track 0: Event 260 (dt=0): type = 80; noteoff: ch 3, par 1c|40
Track 0: Event 261 (dt=40): type = 90; noteon: ch 5, par 34|50
Track 0: Event 262 (dt=0): type = 90; noteon: ch 5, par 34|50
Track 0: Event 263 (dt=0): type = 90; noteon: ch 2, par 28|50
Track 0: Event 264 (dt=0): type = 90; noteon: ch 3, par 1c|40
Track 0: Event 265 (dt=0): type = 90; noteon: ch 1, par 28|70
Track 0: Event 266 (dt=120): type = 80; noteoff: ch 6, par 40|40
Track 0: Event 267 (dt=0): type = 80; noteoff: ch 0, par 40|40
Track 0: Event 268 (dt=0): type = 90; noteon: ch 6, par 41|30
Track 0: Event 269 (dt=0): type = 90; noteon: ch 0, par 41|50
Track 0: Event 270 (dt=120): type = 80; noteoff: ch 1, par 28|4c
Track 0: Event 271 (dt=0): type = 80; noteoff: ch 6, par 41|40
Track 0: Event 272 (dt=0): type = 80; noteoff: ch 0, par 41|40
Track 0: Event 273 (dt=0): type = 90; noteon: ch 6, par 44|30
Track 0: Event 274 (dt=0): type = 90; noteon: ch 0, par 44|50
Track 0: Event 275 (dt=120): type = 80; noteoff: ch 6, par 44|40
Track 0: Event 276 (dt=0): type = 80; noteoff: ch 0, par 44|40
Track 0: Event 277 (dt=0): type = 90; noteon: ch 6, par 41|30
Track 0: Event 278 (dt=0): type = 90; noteon: ch 0, par 41|50
Track 0: Event 279 (dt=80): type = 80; noteoff: ch 5, par 34|40
Track 0: Event 280 (dt=0): type = 80; noteoff: ch 5, par 34|40
Track 0: Event 281 (dt=0): type = 80; noteoff: ch 2, par 28|40
Track 0: Event 282 (dt=0): type = 80; noteoff: ch 3, par 1c|40
Track 0: Event 283 (dt=40): type = 80; noteoff: ch 4, par 3b|40
Track 0: Event 284 (dt=0): type = 80; noteoff: ch 6, par 41|40
Track 0: Event 285 (dt=0): type = 80; noteoff: ch 0, par 41|40
Track 0: Event 286 (dt=0): type = 90; noteon: ch 4, par 3b|60
Track 0: Event 287 (dt=0): type = 90; noteon: ch 5, par 34|50
Track 0: Event 288 (dt=0): type = 90; noteon: ch 2, par 28|50
Track 0: Event 289 (dt=0): type = 90; noteon: ch 3, par 1c|40
Track 0: Event 290 (dt=0): type = 90; noteon: ch 6, par 40|30
Track 0: Event 291 (dt=0): type = 90; noteon: ch 0, par 40|50
Track 0: Event 292 (dt=240): type = 80; noteoff: ch 5, par 34|40
Track 0: Event 293 (dt=0): type = 80; noteoff: ch 2, par 28|40
Track 0: Event 294 (dt=0): type = 80; noteoff: ch 3, par 1c|40
Track 0: Event 295 (dt=0): type = 90; noteon: ch 1, par 28|70
Track 0: Event 296 (dt=0): type = 90; noteon: ch 5, par 32|50
Track 0: Event 297 (dt=0): type = 90; noteon: ch 2, par 26|50
Track 0: Event 298 (dt=0): type = 90; noteon: ch 3, par 1a|40
Track 0: Event 299 (dt=60): type = 80; noteoff: ch 6, par 40|40
Track 0: Event 300 (dt=0): type = 80; noteoff: ch 0, par 40|40
Track 0: Event 301 (dt=0): type = 80; noteoff: ch 1, par 28|60
Track 0: Event 302 (dt=0): type = 90; noteon: ch 6, par 41|30
Track 0: Event 303 (dt=0): type = 90; noteon: ch 0, par 41|50
Track 0: Event 304 (dt=20): type = 90; noteon: ch 1, par 28|70
Track 0: Event 305 (dt=40): type = 80; noteoff: ch 6, par 41|40
Track 0: Event 306 (dt=0): type = 80; noteoff: ch 0, par 41|40
Track 0: Event 307 (dt=0): type = 90; noteon: ch 6, par 44|30
Track 0: Event 308 (dt=0): type = 90; noteon: ch 0, par 44|50
Track 0: Event 309 (dt=20): type = 80; noteoff: ch 1, par 28|56
Track 0: Event 310 (dt=20): type = 90; noteon: ch 1, par 28|70
Track 0: Event 311 (dt=20): type = 80; noteoff: ch 6, par 44|40
Track 0: Event 312 (dt=0): type = 80; noteoff: ch 0, par 44|40
Track 0: Event 313 (dt=0): type = 90; noteon: ch 6, par 41|30
Track 0: Event 314 (dt=0): type = 90; noteon: ch 0, par 41|50
Track 0: Event 315 (dt=40): type = 80; noteoff: ch 1, par 28|4f
Track 0: Event 316 (dt=20): type = 80; noteoff: ch 4, par 3b|40
Track 0: Event 317 (dt=0): type = 80; noteoff: ch 5, par 32|40
Track 0: Event 318 (dt=0): type = 80; noteoff: ch 2, par 26|40
Track 0: Event 319 (dt=0): type = 80; noteoff: ch 3, par 1a|40
Track 0: Event 320 (dt=0): type = 80; noteoff: ch 6, par 41|40
Track 0: Event 321 (dt=0): type = 80; noteoff: ch 0, par 41|40
Track 0: Event 322 (dt=0): type = 90; noteon: ch 4, par 3b|60
Track 0: Event 323 (dt=0): type = 90; noteon: ch 5, par 30|50
Track 0: Event 324 (dt=0): type = 90; noteon: ch 2, par 24|50
Track 0: Event 325 (dt=0): type = 90; noteon: ch 3, par 18|40
Track 0: Event 326 (dt=0): type = 90; noteon: ch 1, par 28|70
Track 0: Event 327 (dt=0): type = 90; noteon: ch 6, par 40|30
Track 0: Event 328 (dt=0): type = 90; noteon: ch 0, par 40|50
Track 0: Event 329 (dt=120): type = 80; noteoff: ch 1, par 28|5a
Track 0: Event 330 (dt=120): type = 80; noteoff: ch 5, par 30|40
Track 0: Event 331 (dt=0): type = 80; noteoff: ch 2, par 24|40
Track 0: Event 332 (dt=0): type = 80; noteoff: ch 3, par 18|40
Track 0: Event 333 (dt=0): type = 90; noteon: ch 5, par 2f|50
Track 0: Event 334 (dt=0): type = 90; noteon: ch 2, par 23|50
Track 0: Event 335 (dt=0): type = 90; noteon: ch 3, par 17|40
Track 0: Event 336 (dt=0): type = 90; noteon: ch 1, par 28|70
Track 0: Event 337 (dt=120): type = 80; noteoff: ch 1, par 28|6a
Track 0: Event 338 (dt=120): type = ff; meta event (length=4): time signature: 03 02 18 08
Track 0: Event 339 (dt=0): type = 80; noteoff: ch 4, par 3b|40
Track 0: Event 340 (dt=0): type = 80; noteoff: ch 6, par 40|40
Track 0: Event 341 (dt=0): type = 80; noteoff: ch 0, par 40|40
Track 0: Event 342 (dt=0): type = 80; noteoff: ch 5, par 2f|40
Track 0: Event 343 (dt=0): type = 80; noteoff: ch 2, par 23|40
Track 0: Event 344 (dt=0): type = 80; noteoff: ch 3, par 17|40
Track 0: Event 345 (dt=0): type = 90; noteon: ch 4, par 40|60
Track 0: Event 346 (dt=0): type = 90; noteon: ch 6, par 45|30
Track 0: Event 347 (dt=0): type = 90; noteon: ch 0, par 45|50
Track 0: Event 348 (dt=0): type = 90; noteon: ch 5, par 2d|50
Track 0: Event 349 (dt=0): type = 90; noteon: ch 2, par 21|50
Track 0: Event 350 (dt=0): type = 90; noteon: ch 3, par 15|40
Track 0: Event 351 (dt=0): type = 90; noteon: ch 1, par 21|70
Track 0: Event 352 (dt=240): type = 80; noteoff: ch 1, par 21|55
Track 0: Event 353 (dt=200): type = 80; noteoff: ch 5, par 2d|40
Track 0: Event 354 (dt=0): type = 80; noteoff: ch 2, par 21|40
Track 0: Event 355 (dt=0): type = 80; noteoff: ch 3, par 15|40
Track 0: Event 356 (dt=40): type = 90; noteon: ch 5, par 2d|50
Track 0: Event 357 (dt=0): type = 90; noteon: ch 2, par 21|50
Track 0: Event 358 (dt=0): type = 90; noteon: ch 3, par 15|40
Track 0: Event 359 (dt=0): type = 90; noteon: ch 1, par 21|70
Track 0: Event 360 (dt=120): type = 80; noteoff: ch 6, par 45|40
Track 0: Event 361 (dt=0): type = 80; noteoff: ch 0, par 45|40
Track 0: Event 362 (dt=0): type = 90; noteon: ch 6, par 46|30
Track 0: Event 363 (dt=0): type = 90; noteon: ch 0, par 46|50
Track 0: Event 364 (dt=120): type = 80; noteoff: ch 1, par 21|4c
Track 0: Event 365 (dt=0): type = 80; noteoff: ch 6, par 46|40
Track 0: Event 366 (dt=0): type = 80; noteoff: ch 0, par 46|40
Track 0: Event 367 (dt=0): type = 90; noteon: ch 6, par 49|30
Track 0: Event 368 (dt=0): type = 90; noteon: ch 0, par 49|50
Track 0: Event 369 (dt=120): type = 80; noteoff: ch 6, par 49|40
Track 0: Event 370 (dt=0): type = 80; noteoff: ch 0, par 49|40
Track 0: Event 371 (dt=0): type = 90; noteon: ch 6, par 46|30
Track 0: Event 372 (dt=0): type = 90; noteon: ch 0, par 46|50
Track 0: Event 373 (dt=80): type = 80; noteoff: ch 5, par 2d|40
Track 0: Event 374 (dt=0): type = 80; noteoff: ch 2, par 21|40
Track 0: Event 375 (dt=0): type = 80; noteoff: ch 3, par 15|40
Track 0: Event 376 (dt=40): type = 80; noteoff: ch 4, par 40|40
Track 0: Event 377 (dt=0): type = 80; noteoff: ch 6, par 46|40
Track 0: Event 378 (dt=0): type = 80; noteoff: ch 0, par 46|40
Track 0: Event 379 (dt=0): type = 90; noteon: ch 4, par 40|60
Track 0: Event 380 (dt=0): type = 90; noteon: ch 5, par 2d|50
Track 0: Event 381 (dt=0): type = 90; noteon: ch 2, par 21|50
Track 0: Event 382 (dt=0): type = 90; noteon: ch 3, par 15|40
Track 0: Event 383 (dt=0): type = 90; noteon: ch 1, par 21|70
Track 0: Event 384 (dt=0): type = 90; noteon: ch 6, par 45|30
Track 0: Event 385 (dt=0): type = 90; noteon: ch 0, par 45|50
Track 0: Event 386 (dt=240): type = 80; noteoff: ch 1, par 21|63
Track 0: Event 387 (dt=200): type = 80; noteoff: ch 5, par 2d|40
Track 0: Event 388 (dt=0): type = 80; noteoff: ch 2, par 21|40
Track 0: Event 389 (dt=0): type = 80; noteoff: ch 3, par 15|40
Track 0: Event 390 (dt=20): type = c0; program change: ch 0, par 9
Track 0: Event 391 (dt=0): type = 80; noteoff: ch 6, par 45|40
Track 0: Event 392 (dt=0): type = 80; noteoff: ch 0, par 45|40
Track 0: Event 393 (dt=20): type = 80; noteoff: ch 4, par 40|40
Track 0: Event 394 (dt=0): type = 90; noteon: ch 5, par 2d|20
Track 0: Event 395 (dt=0): type = 90; noteon: ch 2, par 21|20
Track 0: Event 396 (dt=0): type = 90; noteon: ch 3, par 15|20
Track 0: Event 397 (dt=0): type = 90; noteon: ch 0, par 39|54
Track 0: Event 398 (dt=440): type = 80; noteoff: ch 5, par 2d|40
Track 0: Event 399 (dt=0): type = 80; noteoff: ch 2, par 21|40
Track 0: Event 400 (dt=0): type = 80; noteoff: ch 3, par 15|40
Track 0: Event 401 (dt=40): type = 90; noteon: ch 5, par 2d|20
Track 0: Event 402 (dt=0): type = 90; noteon: ch 2, par 21|20
Track 0: Event 403 (dt=0): type = 90; noteon: ch 3, par 15|20
Track 0: Event 404 (dt=120): type = 80; noteoff: ch 0, par 39|40
Track 0: Event 405 (dt=0): type = 90; noteon: ch 0, par 3a|54
Track 0: Event 406 (dt=120): type = 80; noteoff: ch 0, par 3a|40
Track 0: Event 407 (dt=0): type = 90; noteon: ch 0, par 3d|54
Track 0: Event 408 (dt=120): type = 80; noteoff: ch 0, par 3d|40
Track 0: Event 409 (dt=0): type = 90; noteon: ch 0, par 3a|54
Track 0: Event 410 (dt=80): type = 80; noteoff: ch 5, par 2d|40
Track 0: Event 411 (dt=0): type = 80; noteoff: ch 2, par 21|40
Track 0: Event 412 (dt=0): type = 80; noteoff: ch 3, par 15|40
Track 0: Event 413 (dt=40): type = 80; noteoff: ch 0, par 3a|40
Track 0: Event 414 (dt=0): type = 90; noteon: ch 5, par 2d|20
Track 0: Event 415 (dt=0): type = 90; noteon: ch 2, par 21|20
Track 0: Event 416 (dt=0): type = 90; noteon: ch 3, par 15|20
Track 0: Event 417 (dt=0): type = 90; noteon: ch 0, par 39|54
Track 0: Event 418 (dt=960): type = 80; noteoff: ch 5, par 2d|40
Track 0: Event 419 (dt=0): type = 80; noteoff: ch 2, par 21|40
Track 0: Event 420 (dt=0): type = 80; noteoff: ch 3, par 15|40
Track 0: Event 421 (dt=0): type = 80; noteoff: ch 0, par 39|40
Track 0: Event 422 (dt=960): type = ff; meta event (length=0): end of track
Falcury
Calif
Calif
Posts: 565
Joined: June 25th, 2009, 10:01 pm

Re: MIDI support

Post by Falcury »

Interestingly, while PoP 1.0 only has 18 MIDI instruments, the PRINCE.DAT of PoP 1.3 and 1.4 contains 75 instruments. Although instruments 18-45 are zeroed out, and the first 18 are identical to V1.0. (Maybe instruments 45-75 are used for MT-32 sound, then?)
Falcury wrote: February 21st, 2018, 1:34 am I have started writing a small stand-alone program that will play back the MIDI files.
See the attached program. :)
The sound is quite close to the original, although you can hear that there are still some problems.
In particular, sometimes long notes are not switched off again.
Also, I don't understand what Prince of Persia does with the velocity parameter for MIDI "note on" / "note off" events. So that is simply ignored for now, which maybe has an impact on the sound.
Attachments
popmidi.zip
(575.28 KiB) Downloaded 102 times
User avatar
Norbert
The Prince of Persia
The Prince of Persia
Posts: 5743
Joined: April 9th, 2009, 10:58 pm

Re: MIDI support

Post by Norbert »

Impressive progress.
Is it just my imagination or is the playback (of, for example, Heart.mff) more crisp than what DOSBox gives us?
Falcury
Calif
Calif
Posts: 565
Joined: June 25th, 2009, 10:01 pm

Re: MIDI support

Post by Falcury »

Falcury wrote: February 22nd, 2018, 10:08 pm In particular, sometimes long notes are not switched off again.
Managed to fix that problem.
Also cleaned up the code a bit.

Edit:
Norbert wrote: February 23rd, 2018, 1:06 am Impressive progress.
Is it just my imagination or is the playback (of, for example, Heart.mff) more crisp than what DOSBox gives us?
It definitely sounds good! I suppose the Nuked OPL emulator could be somehow different than the DOSBox OPL emulator?
Attachments
popmidi-1.1.zip
(544.47 KiB) Downloaded 92 times
User avatar
Norbert
The Prince of Persia
The Prince of Persia
Posts: 5743
Joined: April 9th, 2009, 10:58 pm

Re: MIDI support

Post by Norbert »

Falcury wrote: February 23rd, 2018, 1:08 amManaged to fix that problem.
For most files, you're really close now.
Falcury
Calif
Calif
Posts: 565
Joined: June 25th, 2009, 10:01 pm

Re: MIDI support

Post by Falcury »

In this new version, instrument volume and MIDI note velocities are converted to AdLib volume levels, similar to how PoP does it.
Also, now released notes do not get cut off abruptly. (Took me a while to figure this one out...)
I compiled in 64-bit mode last time, and had not tested 32-bit compilation (turns out it was broken...) Fixed that and attached a 32-bit Windows executable this time.

Anyway, the output is now even closer to the DOSBox sounds :)
Although the victory sounds are a bit different. I don't know why.

I also attached some notes I took while looking at David's disassembly of PRINCE.EXE.
Attachments
disasm_midi_notes.txt
(2.64 KiB) Downloaded 99 times
popmidi-1.2.zip
(496.35 KiB) Downloaded 193 times
David
The Prince of Persia
The Prince of Persia
Posts: 2846
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: MIDI support

Post by David »

Falcury wrote: February 24th, 2018, 1:35 am Although the victory sounds are a bit different. I don't know why.
That might be because the Victory*.mff files don't contain any program change events.
That is, they don't specify which instrument to use. So your program uses a default instrument (the first one).

I see you included the MIDIs from PoP 1.3/1.4.
Maybe PoP 1.3 does something special if a MIDI specifies no instrument?

I also tried to play MIDIs from PoP 1.0, but then your player finds only meta events, and I hear nothing.
PoP 1.0 MIDIs have multiple tracks, but your player uses only the first track, which contains no notes.
Maybe you could improve on this in a next version?

Falcury wrote: February 22nd, 2018, 10:08 pm Interestingly, while PoP 1.0 only has 18 MIDI instruments, the PRINCE.DAT of PoP 1.3 and 1.4 contains 75 instruments. Although instruments 18-45 are zeroed out, and the first 18 are identical to V1.0. (Maybe instruments 45-75 are used for MT-32 sound, then?)
Yes, the extra instruments are used in the MT32SND*.DAT files.
You can hear these instruments if you start PoP 1.3 with the adlib parameter.
I tried your player with these sounds (and the instruments file from PoP 1.3), but they sound very much off.
Falcury
Calif
Calif
Posts: 565
Joined: June 25th, 2009, 10:01 pm

Re: MIDI support

Post by Falcury »

Thanks for your feedback, David.
David wrote: February 24th, 2018, 4:22 pm That might be because the Victory*.mff files don't contain any program change events.
That is, they don't specify which instrument to use. So your program uses a default instrument (the first one).

I see you included the MIDIs from PoP 1.3/1.4.
Maybe PoP 1.3 does something special if a MIDI specifies no instrument?
Yeah, that may indeed be the case.
Interestingly, although the 1.0 victory MIDI files also do not specify an instrument either, they have some suspicious-looking track names:

Code: Select all

Track 1: Event   0 (dt=   0): type = ff; meta event (length=2): sequence/track name: hi
Track 2: Event   0 (dt=   0): type = ff; meta event (length=3): sequence/track name: mid
Track 3: Event   0 (dt=   0): type = ff; meta event (length=2): sequence/track name: lo
Track 4: Event   0 (dt=   0): type = ff; meta event (length=2): sequence/track name: hi
Track 5: Event   0 (dt=   0): type = ff; meta event (length=3): sequence/track name: mid
Track 6: Event   0 (dt=   0): type = ff; meta event (length=2): sequence/track name: lo
Track 7: Event   0 (dt=   0): type = ff; meta event (length=2): sequence/track name: hi
Track 8: Event   0 (dt=   0): type = ff; meta event (length=3): sequence/track name: mid
Track 9: Event   0 (dt=   0): type = ff; meta event (length=2): sequence/track name: lo
David wrote: February 24th, 2018, 4:22 pmI also tried to play MIDIs from PoP 1.0, but then your player finds only meta events, and I hear nothing.
PoP 1.0 MIDIs have multiple tracks, but your player uses only the first track, which contains no notes.
Maybe you could improve on this in a next version?
I had not realized that the MIDI files were not identical across versions...
Working on that now. Still need to fix the tracks running out of sync when there is a tempo change event.
David
The Prince of Persia
The Prince of Persia
Posts: 2846
Joined: December 11th, 2008, 9:48 pm
Location: Hungary

Re: MIDI support

Post by David »

Falcury wrote: February 25th, 2018, 9:28 am
David wrote: February 24th, 2018, 4:22 pm That might be because the Victory*.mff files don't contain any program change events.
That is, they don't specify which instrument to use. So your program uses a default instrument (the first one).

I see you included the MIDIs from PoP 1.3/1.4.
Maybe PoP 1.3 does something special if a MIDI specifies no instrument?
Yeah, that may indeed be the case.
I think I found what happens.
Here is how the instruments are initialized in PoP 1.0:

Code: Select all

seg009:6AEF                      adlib_reset_instruments proc near
seg009:6AEF C7 06 48 01 FF FF                    mov     word_1A878, 0FFFFh
seg009:6AF5 33 DB                                xor     bx, bx
seg009:6AF7 88 1E 91 01                          mov     byte_1A8C1, bl
seg009:6AFB B9 10 00                             mov     cx, 10h
seg009:6AFE                      loc_1328E:
seg009:6AFE 8A C3                                mov     al, bl
seg009:6B00 3A 06 77 01                          cmp     al, adlib_instruments_count
seg009:6B04 72 02                                jb      loc_13298
seg009:6B06 2A C0                                sub     al, al
seg009:6B08                      loc_13298:
seg009:6B08 88 87 4A 01                          mov     adlib_curr_instrument[bx], al
seg009:6B0C 43                                   inc     bx
seg009:6B0D E2 EF                                loop    loc_1328E
seg009:6B0F C3                                   retn
seg009:6B0F                      adlib_reset_instruments endp
Basically, the default instrument on each MIDI channel is the instrument with the same number as the channel.

(Actually, there is an additional check that replaces out-of-range instrument numbers with zero.
That first tricked me into thinking that instrument zero is the default.)

I added this code to popmidi.c, at the end of OPL initialization:

Code: Select all

	for (int channel = 0; channel < 16; channel++) {
		channel_instrument[channel] = channel;
	}
Now the Victory*.mff files sound much better, but they are still a bit off.


Falcury wrote: February 24th, 2018, 1:35 am I also attached some notes I took while looking at David's disassembly of PRINCE.EXE.
I'd like to comment on this line:
seg035:0190 byte_1A8C0: adlib_max_volume? ; note: 0x3F is fully silent, 0 is the loudest (not sure what this does exactly)
That variable is set at seg009:6A48 in midi_message_4(), which is called (indirectly) from midi_on_off(), which is in turn called from turn_sound_on_off() (Ctrl+S).
This is how the game mutes MIDI when sounds are off.
Falcury
Calif
Calif
Posts: 565
Joined: June 25th, 2009, 10:01 pm

Re: MIDI support

Post by Falcury »

The attached version has support for MIDI files with multiple tracks.
I also added a --print option, to get a listing of all the events.
David wrote: February 25th, 2018, 11:16 am I think I found what happens.
...
Now the Victory*.mff files sound much better, but they are still a bit off.
Yes, that is a lot better.
I made that change as well in the attached version.
I wonder what would explain the remaining difference with the original.
The 1.0 and 1.3 victory sounds are slightly different, too.

I tried substituting the Nuked emulator with the DOSBox emulator, but that sounded more or less exactly the same.

Don't know the significance of this, but I was wondering about the following:
In adlib_reset_instruments(), the variable byte_1A8C1 (seg035:0191) is also reset.
In midi_message_F() (seg009:69C3), that same variable is potentially set to some value. (I don't know how that would get triggered, though.)
And it is accessed in calc_midi_notes_freq() (seg009:6D47), possibly having some influence on the calculated note frequency.

EDIT:
I figured it out. The variable byte_1A8C1 is the amount of semitones that is added to all notes to make them higher.
A special MIDI sysex message is used to set this value. See midi_message_F() in the disassembly.
The trick is that all MIDI note numbers are by default 12 semitones (one octave) lower than they should be.
Most of the music files contain that special sysex message, which causes them to become 1 (or even 2) octaves higher than the default.
But, the victory music files don't have it... That causes them to sound an octave lower than the rest.
David wrote: February 25th, 2018, 11:16 am
seg035:0190 byte_1A8C0: adlib_max_volume? ; note: 0x3F is fully silent, 0 is the loudest (not sure what this does exactly)
That variable is set at seg009:6A48 in midi_message_4(), which is called (indirectly) from midi_on_off(), which is in turn called from turn_sound_on_off() (Ctrl+S).
This is how the game mutes MIDI when sounds are off.
Ah, OK!
Attachments
popmidi-1.3.zip
(496.37 KiB) Downloaded 94 times
Falcury
Calif
Calif
Posts: 565
Joined: June 25th, 2009, 10:01 pm

Re: MIDI support

Post by Falcury »

It looks like you can also play Prince of Persia 2 MIDI files, if you use PRESETS.DEF as the instruments file. :)
Percussion instruments aren't working, though.
Falcury
Calif
Calif
Posts: 565
Joined: June 25th, 2009, 10:01 pm

Re: MIDI support

Post by Falcury »

New version with the note frequencies fixed. Combining this fix with David's fix for the instruments, the victory music now sounds OK.

There is one remaining difference with the original as far as I can tell: the speed is very slightly too slow (only for some tracks).
For example, if the story 3 (Jaffar enters) song is played during the intro cutscene, the hourglass summoning sound does not match the animation (the sound is slightly delayed).
You can also the tempo difference if you play back the MIDI and the corresponding OGG file at exactly the same time.
However, the playback speed of various other songs seems to be quite OK.
Maybe the frames of the intro cutscene slightly speed up/synchronize the MIDI playback speed in PoP?
Attachments
popmidi-1.4.zip
(497.35 KiB) Downloaded 183 times
User avatar
Norbert
The Prince of Persia
The Prince of Persia
Posts: 5743
Joined: April 9th, 2009, 10:58 pm

Re: MIDI support

Post by Norbert »

So, does this mean SDLPoP will soon support both .ogg and .mid in data/music?
Or maybe you're planning to keep just the .mid files and allow replacing them with .ogg files... or?
Post Reply