Index: uspace/app/modplay/Makefile
===================================================================
--- uspace/app/modplay/Makefile	(revision 7e69e0e9418526683ac074433809479bcfed9ea9)
+++ uspace/app/modplay/Makefile	(revision 7e69e0e9418526683ac074433809479bcfed9ea9)
@@ -0,0 +1,44 @@
+#
+# Copyright (c) 2014 Jiri Svoboda
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# - Redistributions of source code must retain the above copyright
+#   notice, this list of conditions and the following disclaimer.
+# - Redistributions in binary form must reproduce the above copyright
+#   notice, this list of conditions and the following disclaimer in the
+#   documentation and/or other materials provided with the distribution.
+# - The name of the author may not be used to endorse or promote products
+#   derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+
+USPACE_PREFIX = ../..
+LIBS = \
+	$(LIBTRACKMOD_PREFIX)/libtrackmod.a \
+	$(LIBHOUND_PREFIX)/libhound.a \
+	$(LIBPCM_PREFIX)/libpcm.a
+
+EXTRA_CFLAGS = \
+	-I$(LIBTRACKMOD_PREFIX) \
+	-I$(LIBHOUND_PREFIX)/include \
+	-I$(LIBPCM_PREFIX)/include
+BINARY = modplay
+
+SOURCES = \
+	modplay.c
+
+include $(USPACE_PREFIX)/Makefile.common
Index: uspace/app/modplay/modplay.c
===================================================================
--- uspace/app/modplay/modplay.c	(revision 7e69e0e9418526683ac074433809479bcfed9ea9)
+++ uspace/app/modplay/modplay.c	(revision 7e69e0e9418526683ac074433809479bcfed9ea9)
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2014 Jiri Svoboda
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ * - The name of the author may not be used to endorse or promote products
+ *   derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/** @addtogroup edit
+ * @brief Amiga music module player.
+ * @{
+ */
+/**
+ * @file
+ */
+
+#include <errno.h>
+#include <hound/client.h>
+#include <io/console.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <protracker.h>
+#include <trackmod.h>
+
+static bool quit = false;
+
+static void modplay_key_press(kbd_event_t *ev)
+{
+	if ((ev->mods & KM_ALT) == 0 &&
+	    (ev->mods & KM_SHIFT) == 0 &&
+	    (ev->mods & KM_CTRL) != 0) {
+		if (ev->key == KC_Q)
+			quit = true;
+	}
+}
+
+static void modplay_event(cons_event_t *event)
+{
+	switch (event->type) {
+	case CEV_KEY:
+		if (event->ev.key.type == KEY_PRESS) {
+			modplay_key_press(&event->ev.key);
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	trackmod_module_t *mod;
+	trackmod_modplay_t *modplay;
+	hound_context_t *hound;
+	console_ctrl_t *con;
+	cons_event_t event;
+	suseconds_t timeout;
+	pcm_format_t format;
+	void *buffer;
+	size_t buffer_size;
+	int rc;
+
+	if (argc != 2) {
+		printf("syntax: modplay <filename.mod>\n");
+		return 1;
+	}
+
+	con = console_init(stdin, stdout);
+
+	rc = trackmod_protracker_load(argv[1], &mod);
+	if (rc != EOK) {
+		printf("Error loading %s.\n", argv[1]);
+		return 1;
+	}
+
+
+	format.channels = 1;
+	format.sampling_rate = 44100;
+#ifdef __LE__
+	format.sample_format = PCM_SAMPLE_SINT16_LE;
+#else
+	format.sample_format = PCM_SAMPLE_SINT16_BE;
+#endif
+	buffer_size = format.sampling_rate;
+
+	buffer = malloc(buffer_size);
+	if (buffer == NULL) {
+		printf("Error allocating audio buffer.\n");
+		return 1;
+	}
+
+	hound = hound_context_create_playback(argv[1], format, buffer_size);
+	if (hound == NULL) {
+		printf("Error creating playback context.\n");
+		return 1;
+	}
+
+	rc = hound_context_connect_target(hound, HOUND_DEFAULT_TARGET);
+	if (rc != EOK) {
+		printf("Error connecting default audio target (%d).\n", rc);
+		return 1;
+	}
+
+	rc = trackmod_modplay_create(mod, format.sampling_rate, &modplay);
+	if (rc != EOK) {
+		printf("Error setting up playback.\n");
+		return 1;
+	}
+
+	printf("Playing '%s'. Press Ctrl+Q to quit.\n", argv[1]);
+
+	while (true) {
+		timeout = 0;
+		if (console_get_event_timeout(con, &event, &timeout))
+			modplay_event(&event);
+		if (quit)
+			break;
+
+		trackmod_modplay_get_samples(modplay, buffer, buffer_size);
+
+		rc = hound_write_main_stream(hound, buffer, buffer_size);
+		if (rc != EOK) {
+			printf("Error writing audio stream.\n");
+			break;
+		}
+	}
+
+	hound_context_destroy(hound);
+	trackmod_modplay_destroy(modplay);
+	trackmod_module_destroy(mod);
+
+	return 0;
+}
+
+
+/** @}
+ */
