[xmp] Add keyboard controls

Signed-off-by: Claudio Matsuoka <cmatsuoka@gmail.com>
master
Claudio Matsuoka 14 years ago
parent 9d84cec30b
commit d6f9d4aa95
  1. 2
      Makefile.in
  2. 4
      src/Makefile
  3. 171
      src/commands.c
  4. 6
      src/common.h
  5. 22
      src/info.c
  6. 43
      src/main.c

@ -1,7 +1,7 @@
VERSION = 3.9.0
CC = @CC@
CFLAGS = -c @CFLAGS@ @DEFS@ @CPPFLAGS@
CFLAGS = -c -Wall @CFLAGS@ @DEFS@ @CPPFLAGS@
LD = @CC@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@

@ -1,6 +1,6 @@
SRC_OBJS = sound_null.o sound_alsa.o terminal.o info.o options.o \
getopt.o getopt1.o main.o
SRC_OBJS = sound_null.o sound_alsa.o terminal.o info.o commands.o \
options.o getopt.o getopt1.o main.o
SRC_DFILES = Makefile xmp.1 $(SRC_OBJS:.o=.c) common.h getopt.h
SRC_PATH = src

@ -0,0 +1,171 @@
#include <unistd.h>
#include <xmp.h>
#include "common.h"
#ifdef __CYGWIN__
/*
* from daniel åkerud <daniel.akerud@gmail.com>
* date Tue, Jul 28, 2009 at 9:59 AM
*
* Under Cygwin, the read() in process_echoback blocks because VTIME = 0
* is not handled correctly. To fix this you can either:
*
* 1. Enable "tty emulation" in Cygwin using an environment variable.
* http://www.mail-archive.com/cygwin@cygwin.com/msg99417.html
* For me this is _very_ slow and I can see the characters as they are
* typed out when running xmp. I have not investigated why this is
* happening, but there is of course a reason why this mode is not
* enabled by default.
*
* 2. Do a select() before read()ing if the platform is Cygwin.
* This makes Cygwin builds work out of the box with no fiddling around,
* but does impose a neglectible cpu overhead (for Cygwin builds only).
*/
static int stdin_ready_for_reading()
{
fd_set fds;
struct timeval tv;
int ret;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
ret = select(STDIN_FILENO + 1, &fds, NULL, NULL, &tv);
if (ret > 0 && FD_ISSET(STDIN_FILENO, &fds))
return 1;
return 0;
}
#endif
static int read_key()
{
char key;
int ret;
ret = 0;
#if defined HAVE_TERMIOS_H && !defined WIN32
#ifdef __CYGWIN__
if (stdin_ready_for_reading())
#endif
ret = read(0, &key, 1);
#elif defined WIN32
if (kbhit()) {
cmd = getch();
ret = 1;
}
#elif defined __AMIGA__
/* Amiga CLI */
{
BPTR in = Input();
if (WaitForChar(in, 1)) {
Read(in, &key, 1);
ret = 1;
}
}
#else
ret = 0;
#endif
if (ret <= 0) {
return -1;
}
return key;
}
/* Interactive commands */
/* VT100 ESC sequences:
* ESC [ A - up arrow
* ESC [ B - down arrow
* ESC [ C - right arrow
* ESC [ D - left arrow
*/
void read_command(xmp_context ctx, struct control *ctl)
{
int cmd;
cmd = read_key();
if (cmd <= 0)
return;
switch (cmd) {
case 0x1b: /* escape */
cmd = read_key();
if (cmd != '[')
goto cmd_quit;
cmd = read_key();
switch (cmd) {
case 'A':
goto cmd_next_mod;
case 'B':
goto cmd_prev_mod;
case 'C':
goto cmd_next_ord;
case 'D':
goto cmd_prev_ord;
}
break;
case 'q': /* quit */
cmd_quit:
xmp_mod_stop(ctx);
ctl->pause = 0;
ctl->skip = -2;
break;
case 'f': /* jump to next order */
cmd_next_ord:
xmp_ord_next(ctx);
ctl->pause = 0;
break;
case 'b': /* jump to previous order */
cmd_prev_ord:
xmp_ord_prev(ctx);
ctl->pause = 0;
break;
case 'n': /* skip to next module */
cmd_next_mod:
xmp_mod_stop(ctx);
ctl->pause = 0;
ctl->skip = 1;
break;
case 'p': /* skip to previous module */
cmd_prev_mod:
xmp_mod_stop(ctx);
ctl->pause = 0;
ctl->skip = -1;
break;
case 'l':
ctl->loop ^= 1;
break;
case ' ': /* paused module */
ctl->pause ^= 1;
break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
xmp_channel_mute(ctx, cmd - '1', -1);
break;
case '0':
xmp_channel_mute(ctx, 9, -1);
break;
case '!': {
int i;
for (i = 0; i < 10; i++) {
xmp_channel_mute(ctx, i, 0);
}
break; }
}
}

@ -16,6 +16,12 @@ struct options {
char mute[XMP_MAX_CHANNELS];
};
struct control {
int skip;
int loop;
int pause;
};
int set_tty(void);
int reset_tty(void);

@ -2,6 +2,8 @@
#include <string.h>
#include <xmp.h>
static int max_channels = -1;
void info_mod(struct xmp_module_info *mi)
{
int i;
@ -24,10 +26,9 @@ void info_mod(struct xmp_module_info *mi)
}
void info_frame(struct xmp_module_info *mi, int reset)
void info_frame(struct xmp_module_info *mi, int loop, int reset)
{
static int ord = -1, tpo = -1, bpm = -1;
static int max_channels = -1;
int time;
if (reset) {
@ -45,7 +46,7 @@ void info_frame(struct xmp_module_info *mi, int reset)
if (mi->order != ord || mi->bpm != bpm || mi->tempo != tpo) {
printf("\rTempo[%02X] BPM[%02X] Pos[%02X/%02X] "
"Pat[%02X/%02X] Row[ / ] Chn[ / ] 0:00:00.0",
"Pat[%02X/%02X] Row[ / ] Chn[ / ] 0:00:00.0",
mi->tempo, mi->bpm,
mi->order, mi->mod->len - 1,
mi->pattern, mi->mod->pat - 1);
@ -54,15 +55,26 @@ void info_frame(struct xmp_module_info *mi, int reset)
tpo = mi->tempo;
}
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
"%02X/%02X] Chn[%02X/%02X] %3d:%02d:%02d.%d",
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
"%02X/%02X] Chn[%02X/%02X] %c %3d:%02d:%02d.%d",
mi->row, mi->num_rows - 1, mi->virt_used, max_channels,
loop ? 'L' : ' ',
(int)(time / (60 * 600)), (int)((time / 600) % 60),
(int)((time / 10) % 60), (int)(time % 10));
fflush(stdout);
}
void info_pause(struct xmp_module_info *mi, int loop)
{
printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
"%02X/%02X] Chn[%02X/%02X] %c - PAUSED -",
mi->row, mi->num_rows - 1, mi->virt_used, max_channels,
loop ? 'L' : ' ');
fflush(stdout);
}
void info_instruments_compact(struct xmp_module_info *mi)
{
int i, j;

@ -47,8 +47,10 @@ int main(int argc, char **argv)
xmp_context ctx;
struct xmp_module_info mi;
struct options options;
struct control control;
int i;
int first;
int skipprev;
#ifndef WIN32
struct timeval tv;
struct timezone tz;
@ -60,6 +62,7 @@ int main(int argc, char **argv)
#endif
memset(&options, 0, sizeof (struct options));
memset(&control, 0, sizeof (struct control));
options.verbose = 1;
get_options(argc, argv, &options);
@ -87,15 +90,24 @@ int main(int argc, char **argv)
ctx = xmp_create_context();
skipprev = 0;
for (first = optind; optind < argc; optind++) {
printf("\nLoading %s... (%d of %d)\n",
argv[optind], optind - first + 1, argc - first);
if (xmp_load_module(ctx, argv[optind]) < 0) {
fprintf(stderr, "%s: error loading %s\n", argv[0],
argv[i]);
argv[optind]);
if (skipprev) {
optind -= 2;
if (optind < first) {
optind += 2;
}
}
continue;
}
skipprev = 0;
if (xmp_player_start(ctx, options.start, 44100, 0) == 0) {
int new_mod = 1;
@ -121,24 +133,43 @@ int main(int argc, char **argv)
/* Play module */
while (xmp_player_frame(ctx) == 0) {
int old_loop = mi.loop_count;
xmp_player_get_info(ctx, &mi);
if (mi.loop_count > 0)
//printf("%d %d\n", old_loop, mi.loop_count);
if (!control.loop && old_loop != mi.loop_count)
break;
info_frame(&mi, new_mod);
info_frame(&mi, control.loop, new_mod);
sound->play(mi.buffer, mi.buffer_size);
read_command(ctx, &control);
if (control.pause) {
sound->pause();
info_pause(&mi, control.loop);
while (control.pause) {
usleep(100000);
read_command(ctx, &control);
}
sound->resume();
}
new_mod = 0;
options.start = 0;
}
xmp_player_end(ctx);
}
sound->flush();
xmp_release_module(ctx);
printf("\n");
if (control.skip == -1) {
optind -= optind > first ? 2 : 1;
skipprev = 1;
} else if (control.skip == -2) {
break;
}
control.skip = 0;
}
xmp_free_context(ctx);

Loading…
Cancel
Save