diff --git a/src/sound/sound_server.cpp b/src/sound/sound_server.cpp
index dc98e3d84..dbec878bc 100644
--- a/src/sound/sound_server.cpp
+++ b/src/sound/sound_server.cpp
@@ -35,6 +35,8 @@
 --  Includes
 ----------------------------------------------------------------------------*/
 
+#include <numeric>
+
 #include "stratagus.h"
 
 #include "sound_server.h"
@@ -63,104 +65,154 @@ static int MusicVolume = 0;
 static void (*MusicFinishedCallback)();
 
 #ifdef USE_WIN32
-static volatile bool threadWaiting = false;
-static std::string externalFile;
-static HANDLE hWaitingThread;
+static bool externalPlayerIsPlaying = false;
+
+static HANDLE g_hStatusThread;
+static HANDLE g_hDebugThread;
+static HANDLE g_hChildStd_IN_Wr;
 static PROCESS_INFORMATION pi;
 
-DWORD WINAPI MyThreadFunction(LPVOID lpParam) {
-	WaitForSingleObject(pi.hProcess, INFINITE);
-	CloseHandle(pi.hProcess);
-	CloseHandle(pi.hThread);
-	if (threadWaiting) {
-		MusicFinishedCallback();
-		threadWaiting = false;
+static DWORD WINAPI StatusThreadFunction(LPVOID lpParam) {
+	CHAR chStatus;
+	DWORD dwRead = 1;
+	while (1) {
+		if (!ReadFile((HANDLE)lpParam, &chStatus, 1, &dwRead, NULL) || dwRead == 0) {
+			CloseHandle((HANDLE)lpParam);
+			break;
+		}
+		// any write means we finished
+		if (externalPlayerIsPlaying) {
+			externalPlayerIsPlaying = false;
+			MusicFinishedCallback();
+		}
 	}
 	return 0;
 }
 
-static void killPlayingProcess() {
-	if (threadWaiting) {
-		threadWaiting = false;
-		TerminateProcess(pi.hProcess, 0);
-		WaitForSingleObject(hWaitingThread, INFINITE);
-		threadWaiting = false;
-	} else {
+static DWORD WINAPI DebugThreadFunction(LPVOID lpParam) {
+	DWORD dwRead = 1;
+	while (1) {
+		char *chStatus[1024] = {'\0'};
+		if (!ReadFile((HANDLE)lpParam, &chStatus, 1024, &dwRead, NULL) || dwRead == 0) {
+			CloseHandle((HANDLE)lpParam);
+			break;
+		}
+		DebugPrint("%s" _C_ chStatus);
+	}
+	return 0;
+}
+
+static void KillPlayingProcess() {
+	externalPlayerIsPlaying = false;
+	if (g_hChildStd_IN_Wr) {
 		TerminateProcess(pi.hProcess, 0);
+		CloseHandle(g_hChildStd_IN_Wr);
+		g_hChildStd_IN_Wr = NULL;
+		WaitForSingleObject(StatusThreadFunction, 0);
+		WaitForSingleObject(DebugThreadFunction, 0);
 	}
 }
 
 static bool External_Play(const std::string &file) {
-	if (threadWaiting && file == externalFile) {
-		return true;
-	}
-
 	static std::string midi = ".mid";
 	auto it = midi.begin();
 	if (file.size() > midi.size() &&
 			std::all_of(std::next(file.begin(), file.size() - midi.size()), file.end(), [&it](const char & c) { return c == ::tolower(*(it++)); })) {
 		// midi file, use external player, since windows vista+ does not allow midi volume control independent of process volume
+		
 		std::string full_filename = LibraryFileName(file.c_str());
 
-		static const char* midiplayerExe = "stratagus-midiplayer.exe";
-		static const int midiplayerExeSz = strlen(midiplayerExe);
-		
-		// set up a job so our children die with us
-		static bool firstRun = true;
-		static HANDLE hJob;
-		if (firstRun) {
-			hJob = CreateJobObject(NULL, NULL);
-			JOBOBJECT_BASIC_LIMIT_INFORMATION limitInfo;
-			ZeroMemory(&limitInfo, sizeof(limitInfo));
-			limitInfo.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
-			SetInformationJobObject(hJob, JobObjectBasicLimitInformation, &limitInfo, sizeof(limitInfo));
-			AssignProcessToJobObject(hJob, GetCurrentProcess());
-			firstRun = false;
+		// try to communicate with the running midiplayer if we can
+		if (g_hChildStd_IN_Wr != NULL) {
+			// already playing, just send the new song
+			// XXX: timfel: disabled, since the midiplayer behaves weirdly when it receives the next file, just kill and restart
+			KillPlayingProcess();
+			/*
+			// negative value signals a new filename
+			int fileSize = full_filename.size() & 0xffff;
+			char loSize = fileSize & 0xff;
+			char hiSize = (fileSize >> 8) & 0xff;
+			char buf[2] = {loSize, hiSize};
+			externalPlayerIsPlaying = true;
+			if (!WriteFile(g_hChildStd_IN_Wr, buf, 2, NULL, NULL)) {
+				KillPlayingProcess();
+			} else {
+				// then write the filename
+				if (!WriteFile(g_hChildStd_IN_Wr, full_filename.c_str(), fileSize, NULL, NULL)) {
+					KillPlayingProcess();
+				} else {
+					return true;
+				}
+			}
+			*/
 		}
+		// need to start an external player first
 
-		int sz = midiplayerExeSz + 2 + 3 + 2 + full_filename.size() + 1; // exe + 2 spaces + 3 volume + 2 quotes + filename + nullbyte
-		char *cmdline = new char[sz];
-		snprintf(cmdline, sz, "%s %3d \"%s\"", midiplayerExe, std::min(MusicVolume, 127), full_filename.c_str());
-		DebugPrint("Using external command to play midi on windows: %s\n" _C_ cmdline);
-		killPlayingProcess();
+		// setup pipes to player
+		HANDLE hChildStd_IN_Rd = NULL;
+		HANDLE hChildStd_OUT_Rd = NULL;
+		HANDLE hChildStd_OUT_Wr = NULL;
+		HANDLE hChildStd_ERR_Rd = NULL;
+		HANDLE hChildStd_ERR_Wr = NULL;
+		SECURITY_ATTRIBUTES saAttr;
+		saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
+		saAttr.bInheritHandle = TRUE;
+		saAttr.lpSecurityDescriptor = NULL;
+		CreatePipe(&hChildStd_OUT_Rd, &hChildStd_OUT_Wr, &saAttr, 0);
+		CreatePipe(&hChildStd_ERR_Rd, &hChildStd_ERR_Wr, &saAttr, 0);
+		CreatePipe(&hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0);
+		SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0);
+
+		// start the process
+		std::vector<std::string> args = QuoteArguments({ "stratagus-midiplayer.exe", std::to_string(std::min(MusicVolume, 127)), full_filename });
+		std::string cmd = std::accumulate(std::next(args.begin()), args.end(), args[0], [](std::string a, std::string b) { return a + " " + b; });
+		DebugPrint("Using external command to play midi on windows: %s\n" _C_ cmd.c_str());
 		STARTUPINFO si;
 		ZeroMemory(&si, sizeof(si));
 		si.cb = sizeof(si);
+		si.hStdError = hChildStd_ERR_Wr;
+   		si.hStdOutput = hChildStd_OUT_Wr;
+   		si.hStdInput = hChildStd_IN_Rd;
+   		si.dwFlags |= STARTF_USESTDHANDLES;
 		ZeroMemory(&pi, sizeof(pi));
 		bool result = true;
-		if (CreateProcess(NULL, cmdline, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
-			AssignProcessToJobObject(hJob, pi.hProcess);
-			externalFile = file;
-			hWaitingThread = CreateThread(NULL, 0, MyThreadFunction, NULL, 0, NULL);
-			threadWaiting = true;
+		char* cmdline = strdup(cmd.c_str());
+		if (CreateProcess(NULL, cmdline, NULL, NULL, TRUE, /* Handles are inherited */ CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
+			CloseHandle(hChildStd_OUT_Wr);
+			CloseHandle(hChildStd_ERR_Wr);
+      		CloseHandle(hChildStd_IN_Rd);
+			externalPlayerIsPlaying = true;
+			g_hStatusThread = CreateThread(NULL, 0, StatusThreadFunction, hChildStd_OUT_Rd, 0, NULL);
+			g_hDebugThread = CreateThread(NULL, 0, DebugThreadFunction, hChildStd_ERR_Rd, 0, NULL);
 		} else {
 			result = false;
 			DebugPrint("CreateProcess failed (%d).\n" _C_ GetLastError());
 		}
-		delete[] cmdline;
+		free(cmdline);
 		return result;
 	}
-	killPlayingProcess();
+	KillPlayingProcess();
 	return false;
 }
 
 static bool External_IsPlaying() {
-	return threadWaiting;
+	return externalPlayerIsPlaying;
 }
 
 static bool External_Stop() {
 	if (External_IsPlaying()) {
-		killPlayingProcess();
+		KillPlayingProcess();
 		return true;
 	}
 	return false;
 }
 
 static bool External_Volume(int volume, int oldVolume) {
-	if (External_IsPlaying() && externalFile.size() > 0) {
-		if (oldVolume != volume) {
+	if (External_IsPlaying()) {
+		char buf[2] = {0, volume & 0xFF};
+		if (!WriteFile(g_hChildStd_IN_Wr, buf, 2, NULL, NULL)) {
 			External_Stop();
-			External_Play(externalFile);
+			return false;
 		}
 		return true;
 	}
diff --git a/src/sound/win32/midiplayer.c b/src/sound/win32/midiplayer.c
index bc6f35fce..2d8cd49e7 100644
--- a/src/sound/win32/midiplayer.c
+++ b/src/sound/win32/midiplayer.c
@@ -16,6 +16,16 @@
 #include <mmsystem.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <io.h>
+
+HMIXER sMixerHandle;
+HMIDISTRM sOut;
+HANDLE hWaitingThread;
+int sVolume = 127;
+char *sFilename = NULL;
+unsigned int sDeviceId = 0;
 
 #define MAX_BUFFER_SIZE (512 * 12)
 HANDLE event;
@@ -142,7 +152,7 @@ static int is_track_end(const struct evt* e)
 
 static void CALLBACK example9_callback(HMIDIOUT out, UINT msg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
 {
-    switch (msg)
+	switch (msg)
     {
 	case MOM_DONE:
  		SetEvent(event);
@@ -283,7 +293,7 @@ static unsigned int get_buffer(struct trk* tracks, unsigned int ntracks, unsigne
 	return 1;
 }
 
-unsigned int example9(char* filename, int volume)
+unsigned int example9(char *filename)
 {
 	unsigned char* midibuf = NULL;
 	unsigned int midilen = 0;
@@ -299,15 +309,14 @@ unsigned int example9(char* filename, int volume)
 	unsigned int* streambuf = NULL;
 	unsigned int streamlen = 0;
 
-	HMIDISTRM out;
 	MIDIPROPTIMEDIV prop;
 	MIDIHDR mhdr;
-	unsigned int device = 0;
 
 	midibuf = load_file((unsigned char*)filename, &midilen);
 	if(midibuf == NULL)
 	{
-		printf("could not open %s\n", filename);
+		fprintf(stderr, "could not open %s\n", filename);
+		fflush(stderr);
 		return 0;
 	}
 
@@ -338,52 +347,57 @@ unsigned int example9(char* filename, int volume)
     if ((event = CreateEvent(0, FALSE, FALSE, 0)) == NULL)
     	goto error3;
 
-	if (midiStreamOpen(&out, &device, 1, (DWORD)example9_callback, 0, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
+	if (midiStreamOpen(&sOut, &sDeviceId, 1, (DWORD)example9_callback, 0, CALLBACK_FUNCTION) != MMSYSERR_NOERROR)
 		goto error4;
 
 	prop.cbStruct = sizeof(MIDIPROPTIMEDIV);
 	prop.dwTimeDiv = swap_bytes_short(hdr->ticks);
-	if(midiStreamProperty(out, (LPBYTE)&prop, MIDIPROP_SET|MIDIPROP_TIMEDIV) != MMSYSERR_NOERROR)
+	if(midiStreamProperty(sOut, (LPBYTE)&prop, MIDIPROP_SET|MIDIPROP_TIMEDIV) != MMSYSERR_NOERROR)
 		goto error5;
 
 	mhdr.lpData = (char*)streambuf;
 	mhdr.dwBufferLength = mhdr.dwBytesRecorded = streambufsize;
 	mhdr.dwFlags = 0;
 
-	if(midiOutPrepareHeader((HMIDIOUT)out, &mhdr, sizeof(MIDIHDR)) != MMSYSERR_NOERROR)
+	if(midiOutPrepareHeader((HMIDIOUT)sOut, &mhdr, sizeof(MIDIHDR)) != MMSYSERR_NOERROR)
 		goto error5;
 
-	if(midiStreamRestart(out) != MMSYSERR_NOERROR)
+	if(midiStreamRestart(sOut) != MMSYSERR_NOERROR)
 		goto error6;
 
-	if (midiOutSetVolume((HMIDIOUT)out, (DWORD)((volume & 0xFF) << 8) | (volume & 0xFF)) != MMSYSERR_NOERROR) {
-		printf("Cannot set volume, will have to use windows application volume control");
-	}
-
-	printf("buffering...\n");
+	fprintf(stderr, "buffering...\n");
+	fflush(stderr);
 	get_buffer(tracks, ntracks, streambuf, &streamlen);
 	while(streamlen > 0)
 	{
 		mhdr.dwBytesRecorded = streamlen;
 
-		if(midiStreamOut(out, &mhdr, sizeof(MIDIHDR)) != MMSYSERR_NOERROR)
+		if(midiStreamOut(sOut, &mhdr, sizeof(MIDIHDR)) != MMSYSERR_NOERROR)
 			goto error7;
 
 		WaitForSingleObject(event, INFINITE);
 
-		printf("buffering...\n");
+		if (sFilename != filename) {
+			fprintf(stderr, "switch to new file %s.\n", sFilename);
+			fflush(stderr);
+			break;
+		}
+
+		fprintf(stderr, "buffering...\n");
+		fflush(stderr);
 		get_buffer(tracks, ntracks, streambuf, &streamlen);
 	}
-	printf("done.\n");
+	fprintf(stderr, "done.\n");
+	fflush(stderr);
 
 error7:
-	midiOutReset((HMIDIOUT)out);
+	midiOutReset((HMIDIOUT)sOut);
 
 error6:
-	midiOutUnprepareHeader((HMIDIOUT)out, &mhdr, sizeof(MIDIHDR));
+	midiOutUnprepareHeader((HMIDIOUT)sOut, &mhdr, sizeof(MIDIHDR));
 
 error5:
-	midiStreamClose(out);
+	midiStreamClose(sOut);
 
 error4:
 	CloseHandle(event);
@@ -400,13 +414,244 @@ error1:
 	return(0);
 }
 
+DWORD WINAPI MyThreadFunction(LPVOID lpParam) {
+	while (1) {
+		MMRESULT r = midiOutSetVolume((HMIDIOUT)sOut, (DWORD)((sVolume & 0xFF) << 8) | (sVolume & 0xFF));
+		if (r != MMSYSERR_NOERROR) {
+			fprintf(stderr, "Cannot set volume via midi...");
+			switch (r) {
+				case MMSYSERR_INVALHANDLE:
+					fprintf(stderr, "Reason: handle not valid\n");
+					break;
+				case MMSYSERR_NOMEM:
+					fprintf(stderr, "Reason: memory error\n");
+					break;
+				case MMSYSERR_NOTSUPPORTED:
+					fprintf(stderr, "Reason: not supported\n");
+					break;
+				default:
+					fprintf(stderr, "Reason: unknown\n");
+			}
+			fflush(stderr);
+			MMRESULT err = mixerOpen(&sMixerHandle, sDeviceId, 0, 0, 0);
+			if (err) {
+				fprintf(stderr, "ERROR: Can't open Mixer Device! -- %08X\n", err);
+				switch (err) {
+						case MMSYSERR_ALLOCATED:
+							fprintf(stderr, "MMSYSERR_ALLOCATED\n");
+							break;
+						case MMSYSERR_BADDEVICEID:
+							fprintf(stderr, "MMSYSERR_BADDEVICEID\n");
+							break;
+						case MMSYSERR_INVALFLAG:
+							fprintf(stderr, "MMSYSERR_INVALFLAG\n");
+							break;
+						case MMSYSERR_INVALHANDLE:
+							fprintf(stderr, "MMSYSERR_INVALHANDLE\n");
+							break;
+						case MMSYSERR_INVALPARAM:
+							fprintf(stderr, "MMSYSERR_INVALPARAM\n");
+							break;
+						case MMSYSERR_NODRIVER:
+							fprintf(stderr, "MMSYSERR_NODRIVER\n");
+							break;
+						case MMSYSERR_NOMEM:
+							fprintf(stderr, "MMSYSERR_NOMEM\n");
+							break;
+						default:
+							fprintf(stderr, "Reason: unknown\n");
+					}
+					fflush(stderr);
+			} else {
+				MIXERCAPS     mixcaps;
+				MIXERLINE     mixerline;
+				MMRESULT      err;
+				unsigned long i;
+				/* Get info about the first Mixer Device */
+				if (!(err = mixerGetDevCaps((UINT)sMixerHandle, &mixcaps, sizeof(MIXERCAPS)))) {
+					/* Print out the name of each destination line */
+					for (i = 0; i < mixcaps.cDestinations; i++) {
+						mixerline.cbStruct = sizeof(MIXERLINE);
+						mixerline.dwDestination = i;
+
+						if (!(err = mixerGetLineInfo((HMIXEROBJ)sMixerHandle, &mixerline, MIXER_GETLINEINFOF_DESTINATION)))
+						{
+							fprintf(stderr, "Destination #%lu = %s\n", i, mixerline.szName);
+							fflush(stderr);
+						}
+					}
+				}
+				mixerline.cbStruct = sizeof(MIXERLINE);
+				mixerline.dwDestination = 0;
+				mixerline.dwSource = 0;
+
+				if ((err = mixerGetLineInfo((HMIXEROBJ)sMixerHandle, &mixerline, MIXER_GETLINEINFOF_DESTINATION))) {
+					/* An error */
+					fprintf(stderr, "Error #%d calling mixerGetLineInfo()\n", err);
+					switch (err) {
+						case MIXERR_INVALLINE:
+							fprintf(stderr, "MIXERR_INVALLINE\n");
+							break;
+						case MMSYSERR_BADDEVICEID:
+							fprintf(stderr, "MMSYSERR_BADDEVICEID\n");
+							break;
+						case MMSYSERR_INVALFLAG:
+							fprintf(stderr, "MMSYSERR_INVALFLAG\n");
+							break;
+						case MMSYSERR_INVALHANDLE:
+							fprintf(stderr, "MMSYSERR_INVALHANDLE\n");
+							break;
+						case MMSYSERR_INVALPARAM:
+							fprintf(stderr, "MMSYSERR_INVALPARAM\n");
+							break;
+						case MMSYSERR_NODRIVER:
+							fprintf(stderr, "MMSYSERR_NODRIVER\n");
+							break;
+						default:
+							fprintf(stderr, "Reason: unknown\n");
+					}
+					fflush(stderr);
+				} else {
+					fprintf(stderr, "Mixerline: %s\n", mixerline.szName);
+					MIXERCONTROL       mixerControlArray;
+					MIXERLINECONTROLS  mixerLineControls;
+					mixerLineControls.cbStruct = sizeof(MIXERLINECONTROLS);
+					/* Tell mixerGetLineControls() for which line we're retrieving info.
+					We do this by putting the desired line's ID number in dwLineID */
+					mixerLineControls.dwLineID = mixerline.dwLineID;
+					/* We want to fetch info on only 1 control */
+					mixerLineControls.cControls = 1;
+					/* Tell mixerGetLineControls() for which type of control we're
+					retrieving info. We do this by putting the desired control type
+					in dwControlType */
+					mixerLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
+					/* Give mixerGetLineControls() the address of the MIXERCONTROL
+					struct to hold info */
+					mixerLineControls.pamxctrl = &mixerControlArray;
+					/* Tell mixerGetLineControls() how big the MIXERCONTROL is. This
+					saves having to initialize the cbStruct of the MIXERCONTROL itself */
+					mixerLineControls.cbmxctrl = sizeof(MIXERCONTROL);
+					/* Retrieve info on only any volume slider control for this line */
+					if ((err = mixerGetLineControls((HMIXEROBJ)sMixerHandle, &mixerLineControls, MIXER_GETLINECONTROLSF_ONEBYTYPE))) {
+						/* An error */
+						fprintf(stderr, "Error #%d calling mixerGetLineControls()\n", err);
+						fflush(stderr);
+					} else {
+						fprintf(stderr, "Mixercontrol: %s\n", mixerControlArray.szName);
+						fflush(stderr);
+						// try via mixer controls
+						MIXERCONTROLDETAILS_UNSIGNED value;
+						MIXERCONTROLDETAILS          mixerControlDetails;
+						MMRESULT                     err;
+						mixerControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
+						/* Tell mixerSetControlDetails() which control whose value we
+						want to set. We do this by putting the desired control's
+						ID number in dwControlID. The "Speaker Out" line's
+						volume slider has an ID of 0x00000000 */
+						mixerControlDetails.dwControlID = mixerControlArray.dwControlID;
+						/* This is always 1 for a MIXERCONTROL_CONTROLF_UNIFORM control */
+						mixerControlDetails.cChannels = 1;
+						/* This is always 0 except for a MIXERCONTROL_CONTROLF_MULTIPLE control */
+						mixerControlDetails.cMultipleItems = 0;
+						/* Give mixerSetControlDetails() the address of the
+						MIXERCONTROLDETAILS_UNSIGNED struct into which we place the value */
+						mixerControlDetails.paDetails = &value;
+						/* Tell mixerSetControlDetails() how big the MIXERCONTROLDETAILS_UNSIGNED is */
+						mixerControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
+						/* Store the value */
+						value.dwValue = (sVolume & 0xFF) << 8;
+						/* Set the value of the volume slider control for this line */
+						if ((err = mixerSetControlDetails((HMIXEROBJ)sMixerHandle, &mixerControlDetails, MIXER_SETCONTROLDETAILSF_VALUE))) {
+							fprintf(stderr, "Error #%d calling mixerSetControlDetails() ", err);
+							switch (err) {
+								case MIXERR_INVALCONTROL:
+									fprintf(stderr, "Invalid control\n");
+									break;
+								case MMSYSERR_BADDEVICEID:
+									fprintf(stderr, "bad device id\n");
+									break;
+								case MMSYSERR_INVALFLAG:
+									fprintf(stderr, "invalid flag\n");
+									break;
+								case MMSYSERR_INVALHANDLE:
+									fprintf(stderr, "Invalid handle\n");
+									break;
+								case MMSYSERR_INVALPARAM:
+									fprintf(stderr, "Invalid param\n");
+									break;
+								case MMSYSERR_NODRIVER:
+									fprintf(stderr, "No driver\n");
+									break;
+								default:
+									fprintf(stderr, "\n");
+							}
+							fprintf(stderr, "Will have to use windows application volume control.\n");
+							fflush(stderr);
+						}
+					}
+				}
+			}
+		}
+
+		char data1, data2;
+		fprintf(stderr, "read from stdin...");
+		fflush(stderr);
+		if (fread(&data1, sizeof(char), 1, stdin) != 1) {
+			exit(0);
+		} else {
+			if (fread(&data2, sizeof(char), 1, stdin) != 1) {
+				exit(0);
+			}
+		}
+		fprintf(stderr, "got %x %x\n", data1, data2);
+		fflush(stderr);
+		if (data1 > 0) {
+			// new filename
+			short length = data1 | (data2 << 8);
+			fprintf(stderr, "New filename sending: %d bytes\n", length);
+			fflush(stderr);
+			static char buf[0xffff];
+			int lastRead, totalRead = 0;
+			while ((lastRead = fread(buf + totalRead, sizeof(char), length - totalRead, stdin)) > 0 && totalRead < length) {
+				totalRead += lastRead;
+			}
+			if (totalRead < length) {
+				fprintf(stderr, "not enough data, got %d, expected %d bytes\n", totalRead, length);
+				fflush(stderr);
+				exit(0);
+			}
+			buf[length] = '\0';
+			sFilename = buf;
+			fprintf(stderr, "New filename received: %s\n", sFilename);
+			fflush(stderr);
+			SetEvent(event);
+		} else {
+			fprintf(stderr, "New volume received: %d\n", data2);
+			fflush(stderr);
+			sVolume = data2;
+		}
+	}
+	return 0;
+}
+
 int main(int argc, char* argv[])
 {
 	if(argc != 3) {
-		return printf("Usage: %s <volume 0-255> <filename.mid>\n", argv[0]);
+		return fprintf(stderr, "Usage: %s <volume 0-255> <filename.mid>\n", argv[0]);
+	}
+
+	sVolume = atoi(argv[1]);
+	_setmode(_fileno(stdin), _O_BINARY);
+	hWaitingThread = CreateThread(NULL, 0, MyThreadFunction, NULL, 0, NULL);
+
+	sFilename = argv[2];
+
+	while (1) {
+		example9(sFilename);
+		fprintf(stdout, "1");
+		fflush(stdout);
+		WaitForSingleObject(event, INFINITE);
 	}
-	
-	example9(argv[2], atoi(argv[1]));
 
 	return 0;
 }