diff --git a/src/music/dmusic.cpp b/src/music/dmusic.cpp
index 454d886..5d36080 100644
--- a/src/music/dmusic.cpp
+++ b/src/music/dmusic.cpp
@@ -20,6 +20,7 @@
 #include "../os/windows/win32.h"
 #include "../core/mem_func.hpp"
 #include "dmusic.h"
+#include "midifile.hpp"
 
 #include <windows.h>
 #undef FACILITY_DIRECTMUSIC // Needed for newer Windows SDK version.
@@ -382,6 +383,13 @@ void MusicDriver_DMusic::Stop()
 
 void MusicDriver_DMusic::PlaySong(const char *filename, int time_start, int time_end, bool loop)
 {
+	/* read midi file header */
+	MidiFile::SMFHeader midi_header;
+	if (!MidiFile::ReadSMFHeader(filename, midi_header)) {
+		DEBUG(driver, 0, "DirectMusic: could not read MIDI file: %s", filename);
+		return;
+	}
+
 	/* set up the loader object info */
 	DMUS_OBJECTDESC obj_desc;
 	ZeroMemory(&obj_desc, sizeof(obj_desc));
@@ -416,12 +424,11 @@ void MusicDriver_DMusic::PlaySong(const char *filename, int time_start, int time
 		return;
 	}
 
-	/* All original TTD music has a timedivision of 384, while DirectMusic internally
-	 * works with a timedivision of 768 i.e. double. Not hardcoding this would require
-	 * either more addendum data in the baseset files, or reading a couple bytes from
-	 * the MIDI files to get the actual timedivision, and scale accordingly. */
-	time_start *= 2;
-	time_end *= 2;
+	/* DirectMusic internally works with a fixed time subdivision, rather
+	 * than using that of the supplied file. Scale the start/end times to
+	 * match the DirectMusic time subdivision instead. */
+	time_start = time_start * DMUS_PPQ / midi_header.tickdiv;
+	time_end = time_end * DMUS_PPQ / midi_header.tickdiv;
 	segment->SetStartPoint(time_start);
 	/* Enable looping if required */
 	if (time_end > time_start && loop) {
