For each engine:
- Make a new folder detection
- Move detection-related files inside the folder
- Add a new module "enginename/detection"
- Add DETECT_OBJS here
- Adjust the normal engine module to remove detect_objs
- Adjust every file for the new changes.
- Use the fake constructor for message dialog less often
- solve errors regarding comparision between string and u32string in midi
- solve errors in testbed/speech related to ttsMan->say
- fix unsigned comparision warning in tab.cpp
- fix issue with static strings and translations in sdl-graphics
The check to see if background music should be started was implemented as part
of the input processing. As a result, background music would not start if the
game was not getting any input. F.e. on the main menu after starting the game,
if you let the music play until it finishes without doing anything, the game
will go silent. Only after moving the mouse will the background music track
start. The original interpreter starts the background music without needing
user input.
I've fixed this by moving the check to start background music to the timer
loop of the MusicPlayer. I've added a check to prevent background music from
starting while the game is not accepting input.
When loading a savegame, the current background music would play for a few
seconds before the game would set the music for the room that just loaded.
This change stops the music when loading a savegame to prevent this.
When fading out a music track, the original interpreter would keep playing the
track at volume 0. ScummVM would instead stop playing the track, which would
cause the background music track to start playing, while there would be no
music in the original interpreter. Also, when starting playback of a new track,
the original interpreter would restore the volume first, then start playback of
the new track, causing a short part of the old track to be played before the
new track starts. ScummVM would turn the volume back up, but not actually apply
this to the MIDI device, causing new tracks to sometimes play at volume 0.
This change fixes these issues. After fading out, actual playback on the MIDI
device is stopped, but the state of the music player keeps indicating that
music is playing. This prevents the background music from starting. Because
playback is actually stopped, the original interpreter issue of playing a short
bit of the old track when the new track starts is prevented. When resetting
volume when starting a new track, the new volume is now applied to the MIDI
device, which fixes the issue of the new track playing at volume 0.
The 7th Guest has MIDI initialization files for GM and the MT-32 that need to
run for these devices to sound correctly. When loading a game from the ScummVM
main menu, MIDI initialization was not performed.
This change adds this. It runs a slightly changed copy of the game's MIDI init
script when loading a game using the ScummVM menus. It also tracks if MIDI init
has been performed, so it doesn't run a second time when loading a game.
I don't know if the script works properly for the Mac and iOS versions of the
game (or if it is even needed), so I've only enabled it for the DOS versions of
the game for now.
The MIDI music would keep playing while the ScummVM menu was open. This would
cause the music for cutscenes to go out of sync. I've added pausing to the
MusicPlayerMidi to fix this.
The MIDI parser would send All Notes Off events on all MIDI channels as a
safety measure when stopping playback in various situations without first
checking if a track was actually playing. Depending on the specifics of the
code driving the MIDI parser, this could generate many duplicate All Notes Off,
Sustain off and/or Pitch Bend center messages. This is a problem for slow MIDI
hardware like the MT-32, which needs some time to process all these messages.
As a result, the timing at the beginning of the next track could be wrong.
I've introduced checks in stopPlaying, setTrack, unloadMusic and the MIDI
parser destructor so that allNotesOff is called once when a track is playing,
and not a second time when playback has already stopped. Similarly, unloadMusic
does not execute when no music is loaded to prevent duplicate Pitch Bend
messages.
When the MIDI parser wanted to stop all notes on a MIDI device, it would send
an All Notes Off message and, optionally, a Sustain off message on all 16 MIDI
channels. This is inefficient for devices like the MT-32, which uses only 9
channels. The MT-32 hardware is also quite slow, so it is more responsive if it
has to process less messages.
I've added a generic stopAllNotes message to the MIDI driver using the old
method, which can be overriden by more specific implementations in subclasses.
The Miles MIDI driver implementation sends All Notes Off only on the channels
used by the MT-32. There are probably also more efficient implementations
possible for f.e. AdLib.
The Groovie engine implemented some functionality which was later reimplemented
in the generic Miles drivers. These are now used by the engine, but the old
code is still present. I've removed this to clean up the audio code.
XMIDI timbre chunk processing was implemented using a callback. This
reimplements this using an interface for the necessary driver method, which is
a somewhat cleaner solution.
XMIDI data for the MT-32 can contain a timbre chunk which contains the custom
timbre numbers used for a track. Before starting playback of the track, the
timbres must be loaded into the MT-32 using SysEx messages. Each SysEx message
needs a delay before sending the next message to give the MT-32 enough time to
process it.
The delays between the messages were generated using the OSystem::delayMillis
function. This throws off the timing of the MidiParser, which causes MIDI
messages to "pile up", in this case at the start of the track. This change adds
a queue to the Miles MIDI driver, which can store the SysEx messages that must
be executed. The MidiParser suspends playback until the driver has sent all
messages in the queue.
This fixes the start of tracks in The 7th Guest, which had incorrect timing.
Because of the new SysEx queue, MT-32 initialization of The 7th Guest takes a
bit longer than it did before. The game plays an animation of a fixed length
and aborts the initialization if it is not done by the end of the animation.
This problem was already fixed for the GM initialization, so I've applied the
same fix for the MT-32.
This adds using the updated Miles MIDI driver for GM music and using the driver
for source volume scaling.
This reduces the amount of MIDI volume messages when fading, because they are
now only sent on active MIDI channels and if they are different from the
current channel volume. This fixes problems with hardware MIDI devices like the
MT-32 and SC-55, which have trouble dealing with the high number of messages.
The 7th Guest initializes GM devices during the "loading GM drivers"
screen, which is a normal video that plays "audio" that consists of
initialization messages (mostly Roland GS sysexes). The original
interpreter plays this video twice, which is enough time to play the
entire INI_SC.XMI initialization file. ScummVM apparently plays video
a bit faster, and there is not enough time to play the entire init
file. Because of this GM initialization is incomplete.
I've fixed this by making the init video loop until the audio has
finished playing.
Note: I have only tested this with the original DOS version of the
game. I don't know if the file reference I've used to identify the
GM init video is the same on other platforms. If not, this change
might not work and/or have unintended results.
The GM music for The 7th Guest contains several drumkit selection
messages which use an incorrect drumkit number. This relied on a
correction mechanism of the Roland SC-55, which would correct these
numbers to valid selections. This mechanism was not present in later
GS and GM devices, causing error messages and wrong drumkits.
I've fixed this by adding code which simulates the correction
mechanism of the SC-55.
The 7th Guest sends several SysEx messages for Roland GS devices during
startup. ScummVM did not send these messages.
The Groovie MusicPlayerMidi class encapsulates the MidiDriver which is
actually used for sending MIDI events. However, it did not implement the
sysEx method, so the empty implementation of MidiDriver_BASE was used.
I've added a sysEx method which forwards the messages to the actual
MidiDriver.
Loading and returning from subscripts alters the _variables
used, thus are not guaranteed to create a valid save state.
Loading a save should be valid at any time, as long as the
active script being run is restored to the base game script.
If the user enters in an invalid description for the save then it will be
simplified by the saved name cache process in Script::savegame.
I checked this with t7g, but not with the 11th guest or any other Groovie game.
The original in-game loading/saving can still only access the first 10 save
slots (0-9).
Its possible to saving via the GMM when the game is interactive.
Loading a game saved via the gui using the original in-game load menu
works fine.
Saving via the GMM with timestamp works, but only only saves the characters
up to the first non-alpha non-letter characer.
This flag is removed for a few reasons:
* Engines universally set this flag to true for widths > 320,
which made it redundant everywhere;
* This flag functioned primarily as a "force 1x scaler" flag,
since its behaviour was almost completely undocumented and users
would need to figure out that they'd need an explicit non-default
scaler set to get a scaler to operate at widths > 320;
* (Most importantly) engines should not be in the business of
deciding how the backend may choose to render its virtual screen.
The choice of rendering behaviour belongs to the user, and the
backend, in that order.
A nearby future commit restores the default1x scaler behaviour in
the SDL backend code for the moment, but in the future it is my
hope that there will be a better configuration UI to allow users
to specify how they want scaling to work for high resolutions.
All users of BitStream were in fact using a specific, hardcoded variant,
so we can hardcode that variant, removing the need for virtual calls,
and enabling inlining.