mirror of
https://github.com/OpenTTD/OpenTTD.git
synced 2025-03-06 06:15:04 +00:00
Change #6684: Cutting point overrides for music base sets
This improves bad looping of title screen song from Windows TTD, and fixes a long silence at the end of "Can't get there from here" from Windows TTD.
This commit is contained in:
parent
836d25e738
commit
276192f714
@ -142,5 +142,17 @@ GM_TT19.GM = Funk Central
|
|||||||
GM_TT20.GM = Jammit
|
GM_TT20.GM = Jammit
|
||||||
GM_TT21.GM = Movin' On
|
GM_TT21.GM = Movin' On
|
||||||
|
|
||||||
|
; MIDI timecodes where the playback should attemp to start and stop short.
|
||||||
|
; This is to allow fixing undesired silences in original MIDI files.
|
||||||
|
; However not all music drivers may support this.
|
||||||
|
[timingtrim]
|
||||||
|
; Theme has two beats silence at the beginning which prevents clean looping.
|
||||||
|
GM_TT00.GM = 768:53760
|
||||||
|
; Can't Get There From Here from the Windows version has a long silence at the end,
|
||||||
|
; followed by a solo repeat. This isn't in the original DOS version music and is likely
|
||||||
|
; unintentional from the people who converted the music from the DOS version.
|
||||||
|
; Actual song ends after measure 152.
|
||||||
|
GM_TT10.GM = 0:235008
|
||||||
|
|
||||||
[origin]
|
[origin]
|
||||||
default = You can find it on your Transport Tycoon Deluxe CD-ROM.
|
default = You can find it on your Transport Tycoon Deluxe CD-ROM.
|
||||||
|
@ -90,5 +90,17 @@ GM_TT19.GM = Funk Central
|
|||||||
GM_TT20.GM = Jammit
|
GM_TT20.GM = Jammit
|
||||||
GM_TT21.GM = Movin' On
|
GM_TT21.GM = Movin' On
|
||||||
|
|
||||||
|
; MIDI timecodes where the playback should attemp to start and stop short.
|
||||||
|
; This is to allow fixing undesired silences in original MIDI files.
|
||||||
|
; However not all music drivers may support this.
|
||||||
|
[timingtrim]
|
||||||
|
; Theme has two beats silence at the beginning which prevents clean looping.
|
||||||
|
GM_TT00.GM = 768:53760
|
||||||
|
; Can't Get There From Here from the Windows version has a long silence at the end,
|
||||||
|
; followed by a solo repeat. This isn't in the original DOS version music and is likely
|
||||||
|
; unintentional from the people who converted the music from the DOS version.
|
||||||
|
; Actual song ends after measure 152.
|
||||||
|
GM_TT10.GM = 0:235008
|
||||||
|
|
||||||
[origin]
|
[origin]
|
||||||
default = You can find it on your Transport Tycoon Deluxe CD-ROM.
|
default = You can find it on your Transport Tycoon Deluxe CD-ROM.
|
||||||
|
@ -301,6 +301,8 @@ struct MusicSongInfo {
|
|||||||
const char *filename; ///< file on disk containing song (when used in MusicSet class, this pointer is owned by MD5File object for the file)
|
const char *filename; ///< file on disk containing song (when used in MusicSet class, this pointer is owned by MD5File object for the file)
|
||||||
MusicTrackType filetype; ///< decoder required for song file
|
MusicTrackType filetype; ///< decoder required for song file
|
||||||
int cat_index; ///< entry index in CAT file, for filetype==MTT_MPSMIDI
|
int cat_index; ///< entry index in CAT file, for filetype==MTT_MPSMIDI
|
||||||
|
int override_start; ///< MIDI ticks to skip over in beginning
|
||||||
|
int override_end; ///< MIDI tick to end the song at (0 if no override)
|
||||||
};
|
};
|
||||||
|
|
||||||
/** All data of a music set. */
|
/** All data of a music set. */
|
||||||
|
@ -125,6 +125,7 @@ bool MusicSet::FillSetDetails(IniFile *ini, const char *path, const char *full_f
|
|||||||
this->num_available = 0;
|
this->num_available = 0;
|
||||||
IniGroup *names = ini->GetGroup("names");
|
IniGroup *names = ini->GetGroup("names");
|
||||||
IniGroup *catindex = ini->GetGroup("catindex");
|
IniGroup *catindex = ini->GetGroup("catindex");
|
||||||
|
IniGroup *timingtrim = ini->GetGroup("timingtrim");
|
||||||
for (uint i = 0, j = 1; i < lengthof(this->songinfo); i++) {
|
for (uint i = 0, j = 1; i < lengthof(this->songinfo); i++) {
|
||||||
const char *filename = this->files[i].filename;
|
const char *filename = this->files[i].filename;
|
||||||
if (names == NULL || StrEmpty(filename)) {
|
if (names == NULL || StrEmpty(filename)) {
|
||||||
@ -150,15 +151,16 @@ bool MusicSet::FillSetDetails(IniFile *ini, const char *path, const char *full_f
|
|||||||
this->songinfo[i].filetype = MTT_STANDARDMIDI;
|
this->songinfo[i].filetype = MTT_STANDARDMIDI;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *trimmed_filename = filename;
|
||||||
/* As we possibly add a path to the filename and we compare
|
/* As we possibly add a path to the filename and we compare
|
||||||
* on the filename with the path as in the .obm, we need to
|
* on the filename with the path as in the .obm, we need to
|
||||||
* keep stripping path elements until we find a match. */
|
* keep stripping path elements until we find a match. */
|
||||||
for (const char *p = filename; p != NULL; p = strchr(p, PATHSEPCHAR)) {
|
for (; trimmed_filename != NULL; trimmed_filename = strchr(trimmed_filename, PATHSEPCHAR)) {
|
||||||
/* Remove possible double path separator characters from
|
/* Remove possible double path separator characters from
|
||||||
* the beginning, so we don't start reading e.g. root. */
|
* the beginning, so we don't start reading e.g. root. */
|
||||||
while (*p == PATHSEPCHAR) p++;
|
while (*trimmed_filename == PATHSEPCHAR) trimmed_filename++;
|
||||||
|
|
||||||
item = names->GetItem(p, false);
|
item = names->GetItem(trimmed_filename, false);
|
||||||
if (item != NULL && !StrEmpty(item->value)) break;
|
if (item != NULL && !StrEmpty(item->value)) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,6 +175,15 @@ bool MusicSet::FillSetDetails(IniFile *ini, const char *path, const char *full_f
|
|||||||
this->num_available++;
|
this->num_available++;
|
||||||
|
|
||||||
this->songinfo[i].tracknr = j++;
|
this->songinfo[i].tracknr = j++;
|
||||||
|
|
||||||
|
item = timingtrim->GetItem(trimmed_filename, false);
|
||||||
|
if (item != NULL && !StrEmpty(item->value)) {
|
||||||
|
const char *endpos = strchr(item->value, ':');
|
||||||
|
if (endpos != NULL) {
|
||||||
|
this->songinfo[i].override_start = atoi(item->value);
|
||||||
|
this->songinfo[i].override_end = atoi(endpos + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -723,14 +723,6 @@ static void MidiThreadProc(void *)
|
|||||||
while (current_block < current_file.blocks.size()) {
|
while (current_block < current_file.blocks.size()) {
|
||||||
MidiFile::DataBlock &block = current_file.blocks[current_block];
|
MidiFile::DataBlock &block = current_file.blocks[current_block];
|
||||||
|
|
||||||
/* check that block is not in the future */
|
|
||||||
REFERENCE_TIME playback_time = current_time - playback_start_time;
|
|
||||||
if (block.realtime * MIDITIME_TO_REFTIME > playback_time + 3 *_playback.preload_time * MS_TO_REFTIME) {
|
|
||||||
/* Stop the thread loop until we are at the preload time of the next block. */
|
|
||||||
next_timeout = Clamp(((int64)block.realtime * MIDITIME_TO_REFTIME - playback_time) / MS_TO_REFTIME - _playback.preload_time, 0, 1000);
|
|
||||||
DEBUG(driver, 9, "DMusic thread: Next event in %u ms (music %u, ref %lld)", next_timeout, block.realtime * MIDITIME_TO_REFTIME, playback_time);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* check that block isn't at end-of-song override */
|
/* check that block isn't at end-of-song override */
|
||||||
if (current_segment.end > 0 && block.ticktime >= current_segment.end) {
|
if (current_segment.end > 0 && block.ticktime >= current_segment.end) {
|
||||||
if (current_segment.loop) {
|
if (current_segment.loop) {
|
||||||
@ -743,6 +735,14 @@ static void MidiThreadProc(void *)
|
|||||||
next_timeout = 0;
|
next_timeout = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* check that block is not in the future */
|
||||||
|
REFERENCE_TIME playback_time = current_time - playback_start_time;
|
||||||
|
if (block.realtime * MIDITIME_TO_REFTIME > playback_time + 3 *_playback.preload_time * MS_TO_REFTIME) {
|
||||||
|
/* Stop the thread loop until we are at the preload time of the next block. */
|
||||||
|
next_timeout = Clamp(((int64)block.realtime * MIDITIME_TO_REFTIME - playback_time) / MS_TO_REFTIME - _playback.preload_time, 0, 1000);
|
||||||
|
DEBUG(driver, 9, "DMusic thread: Next event in %u ms (music %u, ref %lld)", next_timeout, block.realtime * MIDITIME_TO_REFTIME, playback_time);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* Timestamp of the current block. */
|
/* Timestamp of the current block. */
|
||||||
block_time = playback_start_time + block.realtime * MIDITIME_TO_REFTIME;
|
block_time = playback_start_time + block.realtime * MIDITIME_TO_REFTIME;
|
||||||
@ -1232,8 +1232,8 @@ void MusicDriver_DMusic::PlaySong(const MusicSongInfo &song)
|
|||||||
|
|
||||||
if (!_playback.next_file.LoadSong(song)) return;
|
if (!_playback.next_file.LoadSong(song)) return;
|
||||||
|
|
||||||
_playback.next_segment.start = 0;
|
_playback.next_segment.start = song.override_start;
|
||||||
_playback.next_segment.end = 0;
|
_playback.next_segment.end = song.override_end;
|
||||||
_playback.next_segment.loop = false;
|
_playback.next_segment.loop = false;
|
||||||
|
|
||||||
_playback.do_start = true;
|
_playback.do_start = true;
|
||||||
|
@ -209,10 +209,6 @@ void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DW
|
|||||||
while (_midi.current_block < _midi.current_file.blocks.size()) {
|
while (_midi.current_block < _midi.current_file.blocks.size()) {
|
||||||
MidiFile::DataBlock &block = _midi.current_file.blocks[_midi.current_block];
|
MidiFile::DataBlock &block = _midi.current_file.blocks[_midi.current_block];
|
||||||
|
|
||||||
/* check that block is not in the future */
|
|
||||||
if (block.realtime / 1000 > playback_time) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
/* check that block isn't at end-of-song override */
|
/* check that block isn't at end-of-song override */
|
||||||
if (_midi.current_segment.end > 0 && block.ticktime >= _midi.current_segment.end) {
|
if (_midi.current_segment.end > 0 && block.ticktime >= _midi.current_segment.end) {
|
||||||
if (_midi.current_segment.loop) {
|
if (_midi.current_segment.loop) {
|
||||||
@ -223,6 +219,10 @@ void CALLBACK TimerCallback(UINT uTimerID, UINT, DWORD_PTR dwUser, DWORD_PTR, DW
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
/* check that block is not in the future */
|
||||||
|
if (block.realtime / 1000 > playback_time) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
byte *data = block.data.Begin();
|
byte *data = block.data.Begin();
|
||||||
size_t remaining = block.data.Length();
|
size_t remaining = block.data.Length();
|
||||||
@ -315,8 +315,8 @@ void MusicDriver_Win32::PlaySong(const MusicSongInfo &song)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_midi.next_segment.start = 0;
|
_midi.next_segment.start = song.override_start;
|
||||||
_midi.next_segment.end = 0;
|
_midi.next_segment.end = song.override_end;
|
||||||
_midi.next_segment.loop = false;
|
_midi.next_segment.loop = false;
|
||||||
|
|
||||||
DEBUG(driver, 2, "Win32-MIDI: PlaySong: setting flag");
|
DEBUG(driver, 2, "Win32-MIDI: PlaySong: setting flag");
|
||||||
|
Loading…
Reference in New Issue
Block a user