login

#include <unistd.h>
#include <stdio.h>
#include <termios.h>

#include "qms.h"
#include "smf.h"

#define NEVENTS     (1 << 16)
Event midi_evs[NEVENTS];

#define SEG_LEN 4410

struct termios term_prev;

void
setup_terminal(struct termios *term_prev)
{
    struct termios term_raw;

    /* disable echo and canonical mode */
    tcgetattr(0, term_prev);
    term_raw = *term_prev;
    term_raw.c_lflag &= ~(ECHO | ICANON);
    /* async read */
    term_raw.c_cc[VMIN] = 0;
    term_raw.c_cc[VTIME] = 0; /* in deciseconds */
    tcsetattr(0, TCSAFLUSH, &term_raw);
}

void
restore_terminal(struct termios *term_prev)
{
    tcsetattr(0, TCSAFLUSH, term_prev);
}

void
qms_putsample(int16_t left, int16_t right)
{
    write(1, & left, 2);
    write(1, &right, 2);
}

void
putsilence(unsigned int nsamples)
{
    while (nsamples--)
        qms_putsample(0, 0);
}

#define seek_bck(n) qms_seek(&seeker, seeker.smp_i > (n) ? seeker.smp_i - (n) : 0)
#define seek_fwd(n) qms_seek(&seeker, max_smp_i - seeker.smp_i > (n) ? seeker.smp_i + (n) : max_smp_i-1);

int
main(int argc, char *argv[])
{
    Seeker seeker;
    unsigned int cur_sec, max_sec, max_smp_i;
    unsigned int mark = 0;
    char key;
    int paused, quit;
    int nevs = 0;
    SMFError err;
    if (argc < 2) {
        fprintf(stderr, "usage:\n  %s song.mid\n", argv[0]);
        return 1;
    }
    switch ((err = qms_smf2evs(argv[1], midi_evs, NEVENTS, &nevs))) {
    case SMF_OK:
        break;
    case SMF_NOFILE:
        fprintf(stderr, "file not found\n");
        break;
    case SMF_BADSIG:
        fprintf(stderr, "invalid signature\n");
        break;
    case SMF_BADFMT:
        fprintf(stderr, "unsupported track format\n");
        break;
    case SMF_BADDIV:
        fprintf(stderr, "unsupported division format\n");
        break;
    case SMF_TOOBIG:
        fprintf(stderr, "too many events\n");
        break;
    default:
        fprintf(stderr, "unknown error while loading file\n");
    }
    if (err != SMF_OK)
        return 1;
    setup_terminal(&term_prev);
    max_smp_i = midi_evs[nevs-1].offset;
    max_sec = max_smp_i / R;
    qms_init();
    qms_load(&seeker, midi_evs, nevs);
    qms_seek(&seeker, 0);
    paused = quit = 0;
    while (!quit) {
        if (!paused) {
            quit = qms_play(&seeker, SEG_LEN);
            cur_sec = seeker.smp_i / R;
            fprintf(stderr, " %02u:%02u/%02u:%02u\r",
                    cur_sec/60, cur_sec%60, max_sec/60, max_sec%60);
            fflush(stderr);
        } else {
            putsilence(SEG_LEN);
        }
        if (read(0, &key, 1)) {
            switch (key) {
            case 'q':
                quit = 1;
                break;
            case ' ':
                paused = !paused;
                break;
            case ',':
                seek_bck(5*R);
                break;
            case '.':
                seek_fwd(5*R);
                break;
            case '<':
                seek_bck(30*R);
                break;
            case '>':
                seek_fwd(30*R);
                break;
            case 'm':
                mark = seeker.smp_i;
                break;
            case 'j':
                qms_seek(&seeker, mark);
                break;
            case '0': case '1': case '2': case '3': case '4':
            case '5': case '6': case '7': case '8': case '9':
                qms_seek(&seeker, max_smp_i * (key-'0') / 10);
                break;
            case 'z':
                seeker.dur = seeker.dur < 0xFF ? seeker.dur + 1 : 0xFF;
                break;
            case 'x':
                seeker.dur = 15;
                break;
            case 'c':
                seeker.dur = seeker.dur > 0x00 ? seeker.dur - 1 : 0x00;
                break;
            }
        }
    }
    restore_terminal(&term_prev);
    return 0;
}